Memory leak when using pangocairo for animation

View: New views
1 Messages — Rating Filter:   Alert me  

Memory leak when using pangocairo for animation

by Kyle Schaffrick :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Greetings,

I've isolated a fairly serious memory leak in an application I'm
writing, which involves using pangocairo and cairo to draw text and
graphics at moderately high update rates to produce an animated display.

I managed to create the attached minimal script which reproduces the
leak. It (the repro script) is kind of a hack, in that I'm using
gtk.main_iteration() to turn the main loop inside out, but the problem
originally/still appears when the drawing is initiated from timers in my
normally arranged event-driven application.

I have so far been unable to figure out what exactly is leaking (much
less how to fix it), but it seems to be related to high turnover of of
pango.Layout objects. I've tried using Python's GC debugging output and
Valgrind leakcheck and didn't see any smoking guns, but I'm by no means
a Valgrind wizard.

For a long running process that does this type of drawing (such as an
"realtime status display" sort of application, where I ran into this
leak), the process will continue to grow until VM thrashing and/or
OOM-killing occurs. With high-ish (16 Hz) update rates my Debian test
system with 192MB of physical RAM is completely incapacitated by
thrashing in a matter of 20-30 minutes or so.

I've reproduced this on two disparate systems so far. Does this
reproduce for anyone else, and/or does anyone see any obvious reason
that this script would hemorrhage memory? I'm stumped :)

-Kyle

[pango-leak-demo.py]

import gtk, pangocairo, gc

print """
I have found that the following code which draws repeatedly
updated text with Pango/Cairo causes a continuous and
moderate-to-severe memory leak that I am unable to remedy.

Note that lines marked "###" can be removed and still
trigger the leak.

I will now draw 4000 updates onto a window using Pango
Cairo, destroy/delete the Window, Layout, and Context,
invoke GC, and then idle.
"""

window = gtk.Window()
window.show()

gtk.main_iteration()
gtk.main_iteration()
gtk.main_iteration()
gtk.main_iteration()

print "*** Drawing..."

for i in xrange(4000):
    (sx, sy) = window.get_size()
    window.window.begin_paint_rect( ###
            gtk.gdk.Rectangle(0, 0, sx, sy)) ###
    cr = window.window.cairo_create()
    cr = pangocairo.CairoContext(cr)

    plo = cr.create_layout()

    plo.set_markup(str(i) + " " * (i % 20) + "Drawing") ###
    cr.show_layout(plo) ###

    window.window.end_paint() ###

    gtk.main_iteration(False)

print "*** Destruction/deletion/GC..."

window.hide_all()
window.destroy()
del window, cr, plo
gc.collect()

print """
At this point, on my system, this Python interpreter process
will have continuously grown in virtual image size, reaching
roughly 5 to 7MB larger image at the end of the updates than
near the beginning; neither the ref-counting nor GC, nor any
other dead-chicken-waving I have tried thus far will recover
the leaked memory from within Python.
"""

print "*** Entering idle GTK main-loop."
gtk.main()



_______________________________________________
pygtk mailing list   pygtk@...
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
LightInTheBox - Buy quality products at wholesale price!