Bugs: Browse | Submit New | Admin

[#7896] memory leak of callcc, at specific situation.

Date:
2007-01-16 18:27
Priority:
3
Submitted By:
Park Ji In (mithrandir)
Assigned To:
Shyouhei Urabe (shyouhei)
Category:
Language / Runtime / Core Libraries
State:
Open
Platform:
 
Summary:
memory leak of callcc, at specific situation.

Detailed description
while true
  @x = proc {|c| c}
end

is OK.


while true
  x = callcc {|c| c}
end

is OK, too.

but, 

while true
  @x = callcc {|c| c}
end

consume whole my memory.

I traced this from Generator. when I make some generator object, it doesnt free it's memory. 

while true
  g = Generator.new {|x| (1..3).each {|i| x.yield i}}
end

Of course, I found http://rubyforge.org/tracker/?group_id=426&atid=1698&func=detail&aid=1364

However, this code still consume memory.

Add A Comment: Notepad

Please login


Followup

Message
Date: 2008-11-16 09:53
Sender: Brent Roman

This "leak" appears to be an artifact of MRI's conservative
garbage collector.  It cannot be easily fixed unless the compiler
can be forced to initialize all automatic variables allocated
on the stack.  This behavior would
violate the 'C' programming standard.

Depending upon the compiler options and the target CPU, there
may be unused references to the continuation object from the
previous loop iteration left on the stack when
it is copied in whole by the callcc method.  This happens because
the compiler leaves stack variables that were unused for a particular
function invocation uninitialized.

In your example, these unused references form a linked list of
continuations across the loop iterations.  When the GC tries
to mark such a recursive structure, it
consumes a lot of stack space.  

Workarounds:

Do not return the Continuation passed into the callcc block.
Substitute code like this:

  callcc {|c| @x = c; true}

The occurrence of the leak is platform and compiler
dependent.

When I built x86 Ruby using gcc without optimization
(CFLAGS=-g),
even this caused a memory leak:

  loop { callcc {|c| c}}

However, when I rebuilt it with CFLAGS=-O2, the memory leak only
appeared
when the continuations returned by callcc where assigned to a
variable.

When compiled for the ARM9 with gcc CFLAGS=-Os or CFLAGS=-O2,
everything works as
it should.  No leaks observed.  However, when I changed to CFLAGS=-g
or CFLAGS=-O3,
the original example leaks badly.  These tests were performed
using x86 gcc v3.3.5 + v4.3.2 and
ARM gcc v3.4.5.

Note:
  Just to prove my understanding of the problem,
I was able to stop the leak but hacking in a bit of
code to clear a critical twenty word region of the stack on each
loop{} in the original example.  However, I could not see
a straightforward way to generalize this technique.
Date: 2008-11-08 04:18
Sender: Roger Pack

seems to slowly grow in win32 and linux for me :) [esp. in Linux]--I'm
not sure if it's because of callcc or a poor GC. valgrind doesn't
report anything...hmm.

Thanks!

ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-linux]
Date: 2008-11-08 03:57
Sender: Shyouhei Urabe

A 10-minutes run of reported while loop did not leak on my machine,
FYI.
Date: 2008-11-08 01:23
Sender: Roger Pack

If this is still a concern then could you submit a new copy to
the new tracker:
http://redmine.ruby-lang.org/
--this tracker is being shelved.
Thanks!
-=R
Date: 2008-05-12 07:19
Sender: Roger Pack

wonder if it's related to the other memory leak stuffs
http://betterlogic.com/roger/?p=245

Attached Files:

Name Description Download
No Files Currently Attached

Changes:

Field Old Value Date By
assigned_tonone2007-06-12 02:24zenspider
category_idMisc / Other Standard Library2007-05-29 17:49zenspider
category_idLanguage / Runtime / Core Libraries2007-05-29 15:54zenspider