# Garbage collection oddities

**URL:** <https://www.ruby-forum.com/t/garbage-collection-oddities/172548>\
**Category:** Ruby\
**Created:** [July 23, 2009, 6:53am UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548 "2009-07-23T06:53:40Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dgm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/df788c/32.png) [@dgm](https://www.ruby-forum.com/u/dgm)\
**Post date:** [July 23, 2009, 6:53am UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548/1 "2009-07-23T06:53:40Z")

</div>

Given this code:

class WatchMeDie  
def self.finalizer  
proc do |id|  
puts “Finalized #{id}”  
end  
end  
def initialize  
ObjectSpace.define\_finalizer self, &WatchMeDie.finalizer  
end  
end

a = WatchMeDie.new  
a = nil  
GC.start  
puts ‘end of program’

# #

This produces the expected outcome on 1.8.7:

Finalized 69858803067800  
end of program

On 1.9.1, however, it doesn’t:

end of program  
Finalized 8054060

That is, on 1.9.1, the object is never collected. However, if I create  
two  
such objects:

a = WatchMeDie.new  
b = WatchMeDie.new  
a = nil  
b = nil  
GC.start

Once I do this, the first object is collectible. It seems the most  
recent  
WatchMeDie object will never be collected before the program ends.

Not that any of this really matters, but it complicates what I was  
actually  
testing:

def make\_a\_thread  
Thread.new do  
sleep 1000  
end  
end

def test\_run  
make\_a\_thread  
WatchMeDie.new  
end

a = test\_run  
b = WatchMeDie.new  
a = nil  
GC.start  
puts ‘end of program’

This example works as expected – one WatchMeDie is finalized before  
program  
end, and one after. However, if we change test\_run to:

def test\_run  
make\_a\_thread  
foo = WatchMeDie.new  
end

1.9.1 still works as expected. However, 1.8 does not – because I’ve now  
assigned that object to a local variable, even one that didn’t exist  
when I  
called make\_a\_thread, it now can’t be garbage collected.

One possible workaround, doesn’t:

MyThreadProc = proc do  
sleep 1000  
end  
def make\_a\_thread  
Thread.new &MyThreadProc  
end

In other words, for some bizarre reason, either the thread or the proc  
still  
cares enough about that local scope, and the scope of all its callers,  
to hold  
onto them for posterity.

I’ve worked around this in 1.8 by sending the thread spawning itself to  
another thread, one created with a somewhat cleaner scope and call  
stack. But  
it’s a brutally ugly hack, and there have to be performance  
implications.

Fortunately, 1.9.1 appears to do the right thing, here. Unfortunately,  
this  
kind of stuff is difficult to test. So I’m curious: Is this unique to  
1.8.7, or  
does it exist in 1.8.6, also? And is it likely to be fixed, or should I  
just  
strongly encourage people to upgrade to 1.9?

---

<div class="post-metadata">

**Author:** ![dgm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/df788c/32.png) [@dgm](https://www.ruby-forum.com/u/dgm)\
**Post date:** [July 23, 2009, 3:49pm UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548/2 "2009-07-23T15:49:13Z")

</div>

> That is, on 1.9.1, the object is never collected.

The kicker here is it may not be a bug–it may be that there is a “ghost  
reference” to the object still kicking around somewhere [on the stack or  
what not].  
Because the C calls internally sometimes have extra references that  
aren’t used, they don’t clean the whole stack just by using it, so  
sometimes references are left there.

You could try going down deep in the stack then creating your objects  
def go(n)  
if n==100

# do something

else  
go(n+1)  
end  
end

go(0)  
GC.start

and see if that helps.

In general, however, you’re not guaranteed that finalizers will be  
called at any point–only guaranteed that they’ll be called before the  
program exits (I think that’s what happens anyway).  
GL!  
=r

---

<div class="post-metadata">

**Author:** ![dgm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/df788c/32.png) [@dgm](https://www.ruby-forum.com/u/dgm)\
**Post date:** [July 24, 2009, 10:31pm UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548/3 "2009-07-24T22:31:49Z")

</div>

On Thursday 23 July 2009 09:49:20 am Roger P. wrote:

> > That is, on 1.9.1, the object is never collected.
> 
> The kicker here is it may not be a bug–it may be that there is a “ghost  
> reference” to the object still kicking around somewhere [on the stack or  
> what not].

Right – which I would consider to be a bug.

Or, at the very least, it’s very inconvenient, and not at all what’s  
expected.

> In general, however, you’re not guaranteed that finalizers will be  
> called at any point–only guaranteed that they’ll be called before the  
> program exits (I think that’s what happens anyway).

I understand, which is why I’m not bothered that for some reason, the  
first  
object wasn’t collected until the second one was created. I don’t mind  
if the  
GC is sloppy.

I do mind when it’s an actual leak – in this case, the objects in  
question  
are pretty heavyweight, and if I create a few thousand threads that way,  
I’ll  
have a few thousand of them stuck forever.

---

<div class="post-metadata">

**Author:** ![dgm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/df788c/32.png) [@dgm](https://www.ruby-forum.com/u/dgm)\
**Post date:** [July 28, 2009, 1:29am UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548/4 "2009-07-28T01:29:06Z")

</div>

> I do mind when it’s an actual leak – in this case, the objects in  
> question  
> are pretty heavyweight, and if I create a few thousand threads that way,  
> I’ll  
> have a few thousand of them stuck forever.

If you’re trying to have a multi-threaded app be GC-sane, your options  
are MBARI patches, ruby 1.9, or jruby. AFAIK.  
GL!  
=r

---

<div class="post-metadata">

**Author:** ![dgm](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/df788c/32.png) [@dgm](https://www.ruby-forum.com/u/dgm)\
**Post date:** [July 28, 2009, 3:16am UTC](https://www.ruby-forum.com/t/garbage-collection-oddities/172548/5 "2009-07-28T03:16:24Z")

</div>

On Monday 27 July 2009 07:29:08 pm Roger P. wrote:

> > I do mind when it’s an actual leak – in this case, the objects in  
> > question  
> > are pretty heavyweight, and if I create a few thousand threads that way,  
> > I’ll  
> > have a few thousand of them stuck forever.
> 
> If you’re trying to have a multi-threaded app be GC-sane, your options  
> are MBARI patches, ruby 1.9, or jruby. AFAIK.

Ah, thanks for that.

Yes, this does depend on GC. It does work with 1.9, but I’d been trying  
to  
keep 1.8 compatibility. I guess I can drop that now, and test it on  
jruby.
