strange work of GC

Mike Parker via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Feb 7 21:36:16 PST 2015


On 2/8/2015 11:32 AM, FG wrote:
> On 2015-02-08 at 01:20, Mike Parker wrote:
>> In your case, forget destructors and the destroy method. Just
>> implement a common method on all of your objects that need cleanup
>> (perhaps name it 'terminate') and call that. This gives you the
>> deterministic destruction that you want (the same as calling destroy
>> on each object) while avoiding the possibility that the GC can call
>> your cleanup method.
>
> What is wrong with doing all that in a destructor? I don't know if it is
> just an implementation detail, but a destroyed object is either
> zero-filled or reinitialized to the default, so, if implemented
> correctly, it knows whether a cleanup is required (and I'm assuming that
> a model of simple single ownership is used, like in Qt). Therefore it
> should be safe to use destroy to finalize an object and even to put
> destroy in its destructor in order to perform a controlled cascade
> destruction of all the children that require immediate cleanup (ie.
> releasing expensive non-GC resources, closing connections, etc.). The
> main difference with C++ being that you would only force finalization,
> but then let the GC free the memory in its normal fashion.
>
>
>
First, there are no guarantees about when or if a destructor is going to 
be called. The fact that the current GC calls the destructors of all 
live objects at application shutdown is an implementation detail. If you 
want deterministic destruction, you can not rely on destructors.

Second, if you are going to call destroy on every object to clean them 
up, then in principle that's fine. But now you have to be careful that 
no mistakes slip into the code base, e.g. forgetting to call destroy on 
an object that touches GC memory in its destructor.

By separating resource cleanup from object destruction, you get both 
deterministic cleanup and more freedom in choosing whether or not to 
clean up at all. I used to be obsessive about cleaning up everything at 
app exit (my C background, I suppose). These days, I've come around to 
the view that it's fine just to let the OS handle it. I put a terminate 
method in every class that allocates any sort of resource. If I need to 
free those resources at runtime, I call terminate and let the GC worry 
about the object when it needs to. At app exit, I only call terminate on 
objects that absolutely need to do something before the process exits, 
like writing a final message to a log file, or sending a See You Later 
packet to a server. Everything else I just let go and leave to the OS to 
deal with. There's no reason to do otherwise. In essence, resource 
cleanup only happens when and if I say. That just isn't possible if all 
cleanup is in destructors. You either have to destroy *every* object 
yourself, or be vigilant about which objects you let the GC call 
destructors on.


More information about the Digitalmars-d-learn mailing list