Memory leak

Hi,

I stumbled over a memory leak in ruby gtk or cairo. Here is a short
example:

require ‘gtk3’

class Win < Gtk::Window
def initialize
super
set_default_size 800, 600
@it = 0
self.add_events Gdk::Event::mask::SCROLL_MASK
signal_connect(:scroll_event) {|object, event| redraw; false}
end

def redraw
    p @it
    @it += 1

    @backBuffer = Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 

600
cc = Cairo::Context.new @backBuffer
cc.antialias = :none
cc.set_source_rgb 1.0, 1.0, 1.0
cc.paint

    cb = self.window.create_cairo_context
    cb.set_source @backBuffer
    cb.paint
    true
end

end

win = Win.new
win.show_all
Gtk.main

if you scroll in the window that opens, on scrolls with the mouse wheel,
after ~ 2000 ticks the memory usage on my system is around 3.6 GB. It
seems, that the image memory is not released. If I comment out the line
where the back buffer is created

    @backBuffer = Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 

600

the problem is gone. I don’t know where to look for the solution.

Cheers, detlef

Am 27.03.2014 20:08, schrieb Detlef R.:

If I comment out the line
where the back buffer is created

    @backBuffer = Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 600

the problem is gone. I don’t know where to look for the solution.

I was not precisely in my last mail. I didn’t commented out the back
buffer creation, but moved it to the configure_event handler. That fixed
the problem almost for me, but the bug stays.

Cheers, detlef

On Thu, 2014-03-27 at 20:08 +0100, Detlef R. wrote:

Hi,

I stumbled over a memory leak in ruby gtk or cairo.

Unfortunately I can confirm that problem.
So I really hope Kouhei S. or other experts can comment on it – and
maybe on your previous question too (missing gdk_pixbuf_get_from_window)
for which I have no idea.

For your current problem: Of course generally we would not create a new
surface for each redraw, but create one in initialize method I think.
The cairo problem is depending on cc.paint, if I uncomment it in the
source below I have memory leak. But if I also uncomment #cc.destroy
and #backBuffer.destroy below I have no leak. I always wondered about
that destroy methods… I do not really know something about cairo’s
memory handling and rcairo bindings – maybe cairo painting operations
like cc.paint do increase reference count to the surface?

require ‘gtk3’

class Win < Gtk::Window
def initialize
super
set_default_size 800, 600
@it = 0
self.add_events Gdk::Event::mask::SCROLL_MASK
signal_connect(:scroll_event) {|object, event| redraw; false}
end

def redraw
    p @it
    @it += 1
    backBuffer = Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 

600
cc = Cairo::Context.new backBuffer
#cc.paint
#cc.destroy
#backBuffer.destroy
#GC.start
true
end
end

win = Win.new
win.show_all
Gtk.main

Hi Kou,

I’ve installed rcairo von git with your fix included. For my test
program it fixed the problem, if I start the GC on regular intervals. Is
there a better solution then start the GC on my own every x draw calls?
It’s only a theoretical question, cause I fixed my program on the right
way, as I already wrote.

Thanks allot! Cheers, detlef

Am 31.03.2014 15:37, schrieb Kouhei S.:

Hi,

In [email protected]
“[ruby-gnome2-devel-en] memory leak” on Thu, 27 Mar 2014 20:08:01
+0100,
Detlef R. [email protected] wrote:

I stumbled over a memory leak in ruby gtk or cairo. Here is a short example:

Thanks for your report!
I’ve fixed it in rcairo at master.


kou

On Fri, 2014-04-04 at 19:29 +0200, Detlef R. wrote:

Hi Kou,

I’ve installed rcairo von git with your fix included. For my test
program it fixed the problem, if I start the GC on regular intervals.
Is
there a better solution then start the GC on my own every x draw
calls?
It’s only a theoretical question, cause I fixed my program on the
right
way, as I already wrote.

I tried to find an explanation for that behaviour, and found this nice
page:

Seems that garbage collection is triggered by size of allocated memory
– maybe size of memory allocated by cairo is not visible to GC?

I am using Ruby 2.0 (MRI) and have the same issues as Detlef R…
Manually invoking GC when unused cairo objects exists seems to prevent
excessive heap usage, but may slow down performance.

Question: Should we manually call cairo’s destroy methods when we are
done with cairo objects as in

def redraw
backBuffer = Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 600
cc = Cairo::Context.new backBuffer
cc.paint
#cc.destroy
#backBuffer.destroy
#GC.start
true
end

Unfortunately rcairo’s destroy methods are undocumented, so I was
wondering about it from the beginning.

Best regards,

Stefan S.

On Sat, 2014-04-05 at 08:52 +0900, Kouhei S. wrote:

Here is the recommended way! It is Ruby-ish code. :slight_smile:

Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 600 do |backBuffer|
Cairo::Context.new backBuffer do |cc|
cc.paint
end
end

Nice idea – using block parameters as we do for file operation when
file is automatically closed when block terminates. Works fine, thanks.

Hi,

In [email protected]
“Re: [ruby-gnome2-devel-en] memory leak” on Fri, 04 Apr 2014 22:25:00
+0200,
Stefan S. [email protected] wrote:

true
end

Unfortunately rcairo’s destroy methods are undocumented, so I was
wondering about it from the beginning.

Here is the recommended way! It is Ruby-ish code. :slight_smile:

Cairo::ImageSurface.new Cairo::Format::RGB24, 800, 600 do |backBuffer|
Cairo::Context.new backBuffer do |cc|
cc.paint
end
end

Thanks,

kou