www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GC finalisation

reply "John C" <johnch_atms hotmail.com> writes:
I'm using a disposable pattern on objects that free system resources. One 
reason for this is that you may want to free a class's resources yet keep 
the object itself alive. The interface is as follows:

    interface IDisposable {
        void dispose();
    }

A class typically implements the interface like this:

    class SomeObjectHoldingResources : IDisposable {
        void dispose() {
            // free all resources
        }
        ~this() {
            // dispose should run on finalisation because it may not have 
been called explicitly
            dispose();
        }
    }

As you can see with this design, the dispose method could get called twice: 
once by an explicit call, and by the destructor when the GC collects. To 
prevent this, I could maintain a state tracking whether dispose() has been 
called and only run it from the destructor if the state is 0.

However, I was wondering if we might be able to tell the GC not to run the 
destructor in certain cases. I'm looking for something similar to .NET's 
GC.SuppressFinalizer() and std.gc.addRoot() seems to be what I'm after, and 
indeed calling this after the first dispose() appears to work - that is, it 
prevents the GC from running ~this().

My question is this: is this a safe thing to do? I've not encountered any 
issues as yet but are there any side-effects such as leaks? Is there another 
way to accomplish this?

Thanks. 
Sep 20 2005
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
As I understand it, addRoot() means that the object will never be seen 
as garbage; it will always be considered live.  Thus, you are not only 
preventing the destructor from running, you are also preventing that 
memory from ever being reclaimed.  Unless you plan for that object to 
live forever anyway, then yes, you will have a memory leak.

And of course, if this object points to anything else, then the memory 
leak gets even worse.

John C wrote:
 I'm using a disposable pattern on objects that free system resources. One 
 reason for this is that you may want to free a class's resources yet keep 
 the object itself alive. The interface is as follows:
 
     interface IDisposable {
         void dispose();
     }
 
 A class typically implements the interface like this:
 
     class SomeObjectHoldingResources : IDisposable {
         void dispose() {
             // free all resources
         }
         ~this() {
             // dispose should run on finalisation because it may not have 
 been called explicitly
             dispose();
         }
     }
 
 As you can see with this design, the dispose method could get called twice: 
 once by an explicit call, and by the destructor when the GC collects. To 
 prevent this, I could maintain a state tracking whether dispose() has been 
 called and only run it from the destructor if the state is 0.
 
 However, I was wondering if we might be able to tell the GC not to run the 
 destructor in certain cases. I'm looking for something similar to .NET's 
 GC.SuppressFinalizer() and std.gc.addRoot() seems to be what I'm after, and 
 indeed calling this after the first dispose() appears to work - that is, it 
 prevents the GC from running ~this().
 
 My question is this: is this a safe thing to do? I've not encountered any 
 issues as yet but are there any side-effects such as leaks? Is there another 
 way to accomplish this?
 
 Thanks. 
 
 

Sep 21 2005
next sibling parent Chris Sauls <ibisbasenji gmail.com> writes:
Russ Lewis wrote:
 As I understand it, addRoot() means that the object will never be seen 
 as garbage; it will always be considered live.  Thus, you are not only 
 preventing the destructor from running, you are also preventing that 
 memory from ever being reclaimed.  Unless you plan for that object to 
 live forever anyway, then yes, you will have a memory leak.
 
 However, I was wondering if we might be able to tell the GC not to run 
 the destructor in certain cases. I'm looking for something similar to 
 .NET's GC.SuppressFinalizer() and std.gc.addRoot() seems to be what 
 I'm after, and indeed calling this after the first dispose() appears 
 to work - that is, it prevents the GC from running ~this().

 My question is this: is this a safe thing to do? I've not encountered 
 any issues as yet but are there any side-effects such as leaks? Is 
 there another way to accomplish this?


It is an issue, but could his XYZ.dispose() method call std.gc.removeRoot()? And maybe it would be best to indirectly call the dispose method from a static overload. Aka, something like this: # class XYZ : IDisposable!(XYZ) { # public static void dispose (in XYZ obj) { # obj.dispose(); # delete obj; # } # # public this () { # std.gc.addRoot(...); # } # # public void dispose () { # std.gc.removeRoot(...); # } # } But then the pattern is breaking down. -- Chris Sauls
Sep 21 2005
prev sibling parent reply "John C" <johnch_atms hotmail.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message 
news:dgs3ub$18rk$1 digitaldaemon.com...
 As I understand it, addRoot() means that the object will never be seen as 
 garbage; it will always be considered live.  Thus, you are not only 
 preventing the destructor from running, you are also preventing that 
 memory from ever being reclaimed.  Unless you plan for that object to live 
 forever anyway, then yes, you will have a memory leak.

 And of course, if this object points to anything else, then the memory 
 leak gets even worse.

Best to abandon the idea, then. I'l try my original idea of keeping track of the object's disposed state.
Sep 21 2005
parent James Dunne <james.jdunne gmail.com> writes:
John C wrote:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message 
 news:dgs3ub$18rk$1 digitaldaemon.com...
 
As I understand it, addRoot() means that the object will never be seen as 
garbage; it will always be considered live.  Thus, you are not only 
preventing the destructor from running, you are also preventing that 
memory from ever being reclaimed.  Unless you plan for that object to live 
forever anyway, then yes, you will have a memory leak.

And of course, if this object points to anything else, then the memory 
leak gets even worse.

Best to abandon the idea, then. I'l try my original idea of keeping track of the object's disposed state.

Sep 22 2005