auto classes and finalizers

Bruno Medeiros brunodomedeirosATgmail at SPAM.com
Thu Apr 13 11:53:30 PDT 2006


Sean Kelly wrote:
> Bruno Medeiros wrote:
>> Sean Kelly wrote:
>>
>>> A possible alternative would be for the GC to peform its cleanup in 
>>> two stages.  The first sweep runs all finalizers on orphaned objects, 
>>> and the second releases the memory.  Thus in Eric's example on 
>>> d.D.learn, he would be able legally iterate across his AA and close 
>>> all HANDLEs because the memory would still be valid at that stage.
>>>
>>
>> By orphaned objects, do you mean all objects that are to be reclaimed 
>> by the GC on that cycle? Or just the subset of those objects, that are 
>> not referenced by anyone?
> 
> All objects that are to be reclaimed.  I figured your other suggestion 
> could be used for more complex cases.
> 

That way, you have the guarantee that all references are valid, but some 
instances would have their destructors called multiple times. That's 
likely a behavior that isn't acceptable on some cases.

>>>> Another interesting addition, is to extend the concept of auto to 
>>>> class members. Just as currently auto couples the lifecycle of a 
>>>> variable to the enclosing function, an auto class member would 
>>>> couple the lifecycle of its member to it's owner object. It would 
>>>> get deleted implicitly when then owner object got deleted. Here is 
>>>> another (made up) example:
>>>>
>>>>   class SomeUIWidget {
>>>>     auto Color fgcolor;
>>>>     auto Color bgcolor;
>>>>     auto Size size;
>>>>     auto Image image;
>>>>     ...
>>>>
>>>> The auto members would then have to be initialized on a constructor 
>>>> or something (the exact restrictions might vary, such as being final 
>>>> or not).
>>>
>>> I like this idea as well, though it may require some additional 
>>> bookkeeping to accomplish.  For example, a GC scan may encounter the 
>>> members before the owner, so each member may need to contain a hidden 
>>> pointer to the owner object so the GC knows how to sort things out.
>>
>> Hum, true, it would need some additional bookkeeping, didn't realize 
>> that immediately. The semantics like those that I mentioned in me 
>> previous post would suffice:
>>
>> "When a destructor is called upon an object during a GC (i.e., "as a 
>> finalizer"), then the member references are not valid and cannot be 
>> referenced, *but they can be deleted*. Each will be deleted iff it has 
>> not been deleted already in the reclaiming phase."
>>
>> I don't think your algorithm (having a hidden pointer) would be 
>> necessary (or even feasible), and the one I mentioned before would 
>> suffice.
> 
> Hrm... but what if the owner is simply collected via a normal GC run? In 
> that case, the GC may encounter the member objects before the owner 
> object.  I suppose bookkeeping at the member level may not be necessary, 
> but it may result in an extra scan through the list of objects to be 
> finalized to determine who owns what.
> 
> 
> Sean

The bookkeeping is made by the GC and memory pool manager. A scan 
through the list of objects to be finalized is necessary, but it won't 
be an _extra_ scan. Let me try to explain this way:

*** The current GC algorithm: ***

delete obj:

   m = getMemManagerHandle(obj);
   if(m.isObjectInstance)
     m.obj.destroy(); // calls ~this()
   freeMemory(m);

GC:

   GC determines a set S of instances to be reclaimed (garbage);
   foreach(m in S) {
     delete m;
   }

*** The extended GC algorithm: ***

delete:

   m = getMemManagerHandle(obj);
   if(m.isDeleted)
     return;
   if(m.isObjectInstance)
     m.obj.destroy(); // calls ~this()
   if(!m.isGarbageSet) // If it is not in S
     freeMemory(m);

GC:

   GC determines a set S of instances to be reclaimed (garbage);
   foreach(m in S) {
     m.isGarbage = true;
   }
   foreach(m in S) {
     delete m;
   }
   foreach(m in S) {
     freeMemory(m);
   }


And there we go. No increase in algorithmic complexity. There is only an 
increase in the Memory Manager record size (we need a flag for 
m.isDeleted, and we need it only during a GC run).
The reason we don't freeMemory(m) right after delete m; is because we 
need the bookkeeping of m.isDeleted until the end of the GC run.
The reason we have m.isGarbage is to allow the deletion of objects not 
in S during the GC run. (it is an optimization of doing "S.contains(m)" )

Hope I don't have a bug up there :P

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D



More information about the Digitalmars-d mailing list