[plt-scheme] Memory management and ?custodians

From: Norman Gray (norman at astro.gla.ac.uk)
Date: Mon Mar 8 16:55:46 EST 2010

Matthew, hello again.

On 2010 Mar 3, at 21:03, Matthew Flatt wrote:

> At Wed, 3 Mar 2010 20:40:09 +0000, Norman Gray wrote:
>> I think my question boils down to: how do I (effectively) enforce an
>> ordering in the reclamation of (the Scheme_Object* wrappers of) two
>> inter-related C objects.
>> [...]
>> if the librdf_storage object is reclaimed before one of its
>> librdf_iterator objects, the library complains.
> I don't think you want custodians.

Ah: in that case can I ask a followup question?

In my current code I'm using the current custodian to manage C objects, via scheme_add_managed, and was asking about whether I should be using _multiple_ custodians to enforce cleanup ordering.  I didn't think to mention the current custodian in my original question because I supposed it could be taken for granted.

Your answer makes me worry, though, that the use of custodians, and the use of the memory management tools in scheme/foreign, may be mutually exclusive.  Using the register-finalizer pattern you suggested, my code's now working -- lots of unit tests pass -- but that could simply be coincidence, and I wonder if I'm simply misusing the two FFI approaches by trying to use them together.  Is that plausible?

The other thing I'm starting to think is crucial (rather than a usefully elided detail) is that this cleanup is happening within an exit closer registered with scheme_add_atexit_closer.  Processing what you've said, and thinking it through, I suspect that I basically can't enforce an ordering on the calls to custodian client functions at exit time: I'd guess that the atexit calls ignore any dependencies in order to avoid getting caught in dependency loops.

Thus I seem to be arguing myself into the position that, if I want to free/close a storage object's iterators before freeing/closing the storage object (in the parlance of my original question), and do it at exit time, then I have to enforce that ordering at the C level (messy).  Am I misunderstanding what's going on here?

Thanks for any pointers (ho ho).

>> [ Parenthetically: I'm slightly surprised that the iterator isn't being freed 
>> promptly, as it's inside the equivalent of:
>>    (let ((storage (get-storage ...))
>>      ; do stuff
>>      (let ((iterator (get-iterator storage)))
>>        #t)
>>      (collect-garbage)
>>      ; do more stuff with storage
>>      )
> Switching to 3m could solve that problem. With CGC, it's easy for a
> dead reference to be sitting somewhere that the GC thinks is live.

I shall save this delight for the next refactoring....

Best wishes,


Norman Gray  :  http://nxg.me.uk

Posted on the users mailing list.