digitalmars.D.learn - GC finalisation
- "John C" <johnch_atms hotmail.com> Sep 20 2005
- Russ Lewis <spamhole-2001-07-16 deming-os.org> Sep 21 2005
- Chris Sauls <ibisbasenji gmail.com> Sep 21 2005
- "John C" <johnch_atms hotmail.com> Sep 21 2005
- James Dunne <james.jdunne gmail.com> Sep 22 2005
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
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
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
"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
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









Chris Sauls <ibisbasenji gmail.com> 