On Nov 29, 2011, at 6:43 AM, Garthy D wrote:

> 
> Hi.
> 
> I was wondering if running the (mark and sweep?) garbage collector manually is supposed to collect (and call define_finalizer procs on) objects with no remaining references. I would expect that the answer is yes, but it doesn't seem to actually work that way.
> 
> When I run the script below (based on some examples online that apparently avoid some of the problems with define_finalizer), the output suggests that the finalizer for an allocated and unused object of class A isn't actually being called until *after* the garbage collection is complete and the program has reached the end. This suggests that calling the garbage collector doesn't actually cause unreferenced objects to be reaped immediately.
> 
> Is there a fault in my assumptions or the script below?
> 
> If you wrap the A.new in a loop instead, eventually it'll free up the other instances of A en-masse (ie. calling the GC doesn't seem to do it, but flooding memory until the GC triggers does).
> 
> I have seen similar behavior in a large embedded Ruby program that I am working on. In this case the Ruby objects in question have instance variables that reference textures, and I really need the finalizer to be called when all of the references to the textures are lost, so as to free up the texture memory. At the moment they are being finalised at program exit, when the available texture memory has long run out. This isn't good, and it means I need to rewrite every potential bit of this code to use manual reference counting.
> 
> So basically: If the garbage collector is called, are objects with no remaining references supposed to be reaped during the call, and their defined finalizers called? Whatever the answer- why is that? Is there an official word on how this is supposed to work, and what can (and can't) be relied upon?

The finalizer behavior is undefined at the language level because it is runtime-dependent. Try running your code on JRuby or Rubinius. Each has a different GC than MRI and will thus behave differently. The GC in MRI is also different between 1.8 and 1.9 when it was replaced with a more efficient mechanism.

You can't rely on the GC calling your finalizers when the object is reaped. Each runtime will have different behavior.

I have a project that uses a finalizer to deallocate some native memory (allocated via FFI). I see the same behavior as you describe on MRI. On JRuby and Rubinius the finalizer is called "closer in time" to when the object is reaped but I don't know for certain that it is happening in the same cycle as the GC. For all I know it's pushing the finalizer reference onto another queue somewhere and getting to it during its idle time.

So, try another runtime or modify your code to do refcounting.

cr