The D documentation at http://dlang.org/class.html#destructors states that

"The garbage collector is not guaranteed to run the destructor for all unreferenced objects."

However I am a little contused as to what this actually means. Is this saying that a GC implementation can choose to not call destructors when it collects the objects they belong to? If this is the case I can hardly see a point in destructors at all given delete is being deprecated.

I could also interpret this as meaning that the garbage collector may simply never collect some objects. Which while more understandable seems just as worrying. Does it imply the collector may cause leaks?

As a bit of a follow up but I hope still in the scope of the same question, if one of these are indeed the case, is there any documentation available which explains how to manage objects which require destructors such as those representing resources other than memory if the garbage collector cannot be used in these cases as seems to be implied here?

1

There are 1 answers

2
Adam D. Ruppe On BEST ANSWER

It means both: the garbage collector may never run (the GC in D today only runs when you ask it for memory and it is already at its threshold or at program termination) and when it does run, it may not collect something, mostly due to false pointers on 32 bit. (A random value looks like a pointer to the data, so the GC thinks it might be and thus doesn't collect the object.)

The false pointer thing is extremely rare on 64 bit, but somewhat easy to trigger in 32 bit code, and not running the GC is actually a common thing you aim for for performance: you want it to run when you can afford a brief pause as it collects garbage.

If an object represents some other resource, you might want to avoid using it in a garbage collection environment at all. Instead, wrap it in a struct rather than class and maintain ownership of it at some top level scope, passing it down as pointers to the struct, or put it in something like RefCounted (see std.typecons) so it is managed that way.

Alternatively, write a dispose method on your class and call it manually when you're done:

class YourDisposable {
    HANDLE managed_object;
    this() { managed_object = acquire_resource(); }
    void dispose() {
       if(managed_object !is null) {
             release_resource(managed_object);
             managed_object = null;
       }
    }

    ~this() {
         dispose();
    }
}

 auto obj = new YourDisposable();
 scope(exit) obj.dispose();

This way, you typically destroy it yourself so it is predictably released, but the GC can also be used in case you miss a spot or ownership is too hard to manage manually.