memory leaks, 0.54.1 with .2a modifications

There does seem to be a memory problem when using Python and GTK+. Have
you seen the pygtk FAQ 8.4 "Is there a resource leak? Why do I run out
of memory using Pixbuf?"

From looking at matplotlib/backends/backend_gtk.py I noticed every

FigureCanvasGTK.draw() operation allocates memory for a new pixmap and a
new graphics context. So looping 200 times in your first test script
allocates memory for 200 pixmaps and 200 graphics contexts, yet the
pixmap size has not changed and the graphics context has not changed. I
think it would be more memory efficient to create a pixmap and continue
using it until a larger pixmap is required. The graphics context does
not change its default settings, so it does little, but is required for
the GDK calls, again it looks to me like it would be better to create
one and reuse it.

Here are some changes I made to matplotlib/backends/backend_gtk.py I
estimate saves around 10% of the memory leak.
However I can't check that it plots correctly properly because I
currently get a plot of a black rectangle in GTK mode (GTKAgg works OK),
which I think was mentioned as a numarray problem with the latest
matplotlib release.

FigureCanvasGTK.__init__(self,figure): # add the following line
        self.pixmap_width, self.pixmap_height = -1, -1 # new

FigureCanvasGTK.draw(self): # replace with this:
    def draw(self):
        if not self._doplot: return
        drawable = self.window
        if drawable is None: return
        
        width = int(self.figure.bbox.width())
        height = int(self.figure.bbox.height())

        if width > self.pixmap_width or height > self.pixmap_height:
            self._gpixmap = gtk.gdk.Pixmap(drawable, width, height)
            self.pixmap_width = width
            self.pixmap_height = height

        self.figure.draw( RendererGTK(self, self._gpixmap,
self.figure.dpi) )
        drawable.draw_drawable(self._ggc, self._gpixmap, 0, 0, 0, 0,
width, height)

FigureCanvasGTK.realize(self, widget): # add the following line:
        self._ggc = self.window.new_gc()

Regards
Steve

Steve,

There does seem to be a memory problem when using Python and GTK+. Have
you seen the pygtk FAQ 8.4 "Is there a resource leak? Why do I run out
of memory using Pixbuf?"

Yes, I saw that, tried putting in explicit gc.collect() calls, but it didn't help. I concluded the problem was different. I also looked at the draw function in backend_gtk.py. What I don't understand is how and when the no-longer-used gtk objects (pixmap, etc) really can and should be de-allocated. Evidently they persist when the python reference to them goes out of scope.

Thanks for your changes.

Eric

From looking at matplotlib/backends/backend_gtk.py I noticed every

FigureCanvasGTK.draw() operation allocates memory for a new pixmap and a
new graphics context. So looping 200 times in your first test script
allocates memory for 200 pixmaps and 200 graphics contexts, yet the
pixmap size has not changed and the graphics context has not changed. I
think it would be more memory efficient to create a pixmap and continue
using it until a larger pixmap is required. The graphics context does
not change its default settings, so it does little, but is required for
the GDK calls, again it looks to me like it would be better to create
one and reuse it.

Here are some changes I made to matplotlib/backends/backend_gtk.py I
estimate saves around 10% of the memory leak.
However I can't check that it plots correctly properly because I
currently get a plot of a black rectangle in GTK mode (GTKAgg works OK),
which I think was mentioned as a numarray problem with the latest
matplotlib release.

FigureCanvasGTK.__init__(self,figure): # add the following line
       self.pixmap_width, self.pixmap_height = -1, -1 # new

FigureCanvasGTK.draw(self): # replace with this:

···

   def draw(self):
       if not self._doplot: return
       drawable = self.window if drawable is None: return

              width = int(self.figure.bbox.width())
       height = int(self.figure.bbox.height())

       if width > self.pixmap_width or height > self.pixmap_height:
           self._gpixmap = gtk.gdk.Pixmap(drawable, width, height)
           self.pixmap_width = width
           self.pixmap_height = height

       self.figure.draw( RendererGTK(self, self._gpixmap,
self.figure.dpi) )
       drawable.draw_drawable(self._ggc, self._gpixmap, 0, 0, 0, 0,
width, height)

FigureCanvasGTK.realize(self, widget): # add the following line:
       self._ggc = self.window.new_gc()

Regards
Steve