Hi Chuck,

Thankyou for the fast reply. :)

On 29/11/11 23:42, Chuck Remes wrote:
> 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.

Thankyou for the information. Leaving the GC/finalizer behaviour 
undefined is reasonable- it just causes me problems in my particular 
circumstances. :/

I haven't experimented with other Ruby implementations (just the MRI), 
but it is good to know that other implementations may also handle it 
differently. Basically: I can assume very little about how the GC might 
behave.

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

Yes. Unfortunate for me, but understandable.

> 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.

It's nice to know that I'm not going crazy. ;) Because a great deal of 
information online suggests that the memory is cleaned up immediately 
(on GC), I had assumed this was the case, and that I must have had a bug 
or unknown reference to certain objects somewhere in my code. As you can 
probably imagine, that took some time to track down.

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

I was hoping to avoid needing to layer reference counting on top of 
things, but I might not have a great deal of choice in the matter. I'll 
just have to think of ways to make it work well in my particular 
circumstances. Darn.

Garth