digitalmars.D - Manual Deletion from Destructor
- dsimcha (21/21) Mar 14 2009 I sometimes run into false pointer issues when using very large data
- Chad J (15/41) Mar 14 2009 http://www.digitalmars.com/d/2.0/class.html#Destructor
- Jarrett Billingsley (5/9) Mar 14 2009 not
- Andrei Alexandrescu (7/33) Mar 14 2009 You can't call delete against a struct object, so the above wouldn't
- dsimcha (10/43) Mar 14 2009 No, the problem is that there may be things that look like pointers poin...
- Andrei Alexandrescu (3/20) Mar 14 2009 Thanks for the info, that's very interesting.
- Sean Kelly (5/11) Mar 14 2009 It's conservative for everything, unless you count marking an entire
- Andrei Alexandrescu (5/18) Mar 14 2009 Ouch. Yet another place where introspection could help lots.
- dsimcha (24/27) Mar 14 2009 This is a corner case, but run the following code:
- BCS (2/7) Mar 14 2009 If you can be shure ~this will get called, you might switch to malloc.
- Frits van Bommel (5/14) Mar 14 2009 If you do this, don't forget to register and unregister the memory with
I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like: class Foo { // Allocated on GC heap. private HugeDataStructure hugeDataStructure; ~this() { // hugeDataStructure _should_ be GC'd when the Foo instance // is GC'd because hugeDataStructure is guaranteed never // to escape. It may not be b/c // of false pointer issues. Delete it manually when instance // of Foo that owns it is GC'd. delete hugeDataStructure; } } The point is that the destructor for instances of Foo is called by the GC, not manually. The GC may have already realized that hugeDataStructure is not reachable. Does this make the delete statement in the d'tor unsafe, or is it still ok? Note: You can assume that hugeDataStructure doesn't have its own destructor, so delete just frees memory.
Mar 14 2009
dsimcha wrote:I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like: class Foo { // Allocated on GC heap. private HugeDataStructure hugeDataStructure; ~this() { // hugeDataStructure _should_ be GC'd when the Foo instance // is GC'd because hugeDataStructure is guaranteed never // to escape. It may not be b/c // of false pointer issues. Delete it manually when instance // of Foo that owns it is GC'd. delete hugeDataStructure; } } The point is that the destructor for instances of Foo is called by the GC, not manually. The GC may have already realized that hugeDataStructure is not reachable. Does this make the delete statement in the d'tor unsafe, or is it still ok? Note: You can assume that hugeDataStructure doesn't have its own destructor, so delete just frees memory.http://www.digitalmars.com/d/2.0/class.html#Destructor http://www.digitalmars.com/d/1.0/class.html#Destructor both say: "The garbage collector is not guaranteed to run the destructor for all unreferenced objects. Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. This means that destructors cannot reference sub objects. This rule does not apply to auto objects or objects deleted with the DeleteExpression, as the destructor is not being run by the garbage collector, meaning all references are valid." I think you are violating that rule.
Mar 14 2009
On Sat, Mar 14, 2009 at 11:53 AM, dsimcha <dsimcha yahoo.com> wrote:The point is that the destructor for instances of Foo is called by the GC=, notmanually. =A0 The GC may have already realized that hugeDataStructure is =notreachable. =A0Does this make the delete statement in the d'tor unsafe, or=is itstill ok?Accessing or deleting any GC-managed memory in a destructor is unsafe,
Mar 14 2009
dsimcha wrote:I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like: class Foo { // Allocated on GC heap. private HugeDataStructure hugeDataStructure; ~this() { // hugeDataStructure _should_ be GC'd when the Foo instance // is GC'd because hugeDataStructure is guaranteed never // to escape. It may not be b/c // of false pointer issues. Delete it manually when instance // of Foo that owns it is GC'd. delete hugeDataStructure; } } The point is that the destructor for instances of Foo is called by the GC, not manually. The GC may have already realized that hugeDataStructure is not reachable. Does this make the delete statement in the d'tor unsafe, or is it still ok? Note: You can assume that hugeDataStructure doesn't have its own destructor, so delete just frees memory.You can't call delete against a struct object, so the above wouldn't compile. What may solve your problem is calling GC.hasNoPointers against the block of memory in which hugeDataStructure lives. But before that... isn't the current GC non-conservative for heap-allocated objects? I thought it's only conservative for stack objects. Andrei
Mar 14 2009
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articledsimcha wrote:No, the problem is that there may be things that look like pointers pointing to internal regions of hugeDataStructure. For example, let's say hugeDataStructure is a 100-megabyte array. It's a pretty big target for false pointers, so even though the only legitimate reference is from the instance of Foo that owns it, hugeDataStructure might never get GC'd. In my specific case, hugeDataStructure is a large associative array. A few nodes don't get freed properly, leading to heap fragmentation and massive memory usage. (I've created my own AA delete function, which I know works when not used from a destructor like the above example, see Bugzilla 2105).I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like: class Foo { // Allocated on GC heap. private HugeDataStructure hugeDataStructure; ~this() { // hugeDataStructure _should_ be GC'd when the Foo instance // is GC'd because hugeDataStructure is guaranteed never // to escape. It may not be b/c // of false pointer issues. Delete it manually when instance // of Foo that owns it is GC'd. delete hugeDataStructure; } } The point is that the destructor for instances of Foo is called by the GC, not manually. The GC may have already realized that hugeDataStructure is not reachable. Does this make the delete statement in the d'tor unsafe, or is it still ok? Note: You can assume that hugeDataStructure doesn't have its own destructor, so delete just frees memory.You can't call delete against a struct object, so the above wouldn't compile. What may solve your problem is calling GC.hasNoPointers against the block of memory in which hugeDataStructure lives. But before that... isn't the current GC non-conservative for heap-allocated objects? I thought it's only conservative for stack objects. Andrei
Mar 14 2009
dsimcha wrote:== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleThanks for the info, that's very interesting. AndreiYou can't call delete against a struct object, so the above wouldn't compile. What may solve your problem is calling GC.hasNoPointers against the block of memory in which hugeDataStructure lives. But before that... isn't the current GC non-conservative for heap-allocated objects? I thought it's only conservative for stack objects. AndreiNo, the problem is that there may be things that look like pointers pointing to internal regions of hugeDataStructure. For example, let's say hugeDataStructure is a 100-megabyte array. It's a pretty big target for false pointers, so even though the only legitimate reference is from the instance of Foo that owns it, hugeDataStructure might never get GC'd. In my specific case, hugeDataStructure is a large associative array. A few nodes don't get freed properly, leading to heap fragmentation and massive memory usage. (I've created my own AA delete function, which I know works when not used from a destructor like the above example, see Bugzilla 2105).
Mar 14 2009
Andrei Alexandrescu wrote:You can't call delete against a struct object, so the above wouldn't compile. What may solve your problem is calling GC.hasNoPointers against the block of memory in which hugeDataStructure lives. But before that... isn't the current GC non-conservative for heap-allocated objects? I thought it's only conservative for stack objects.It's conservative for everything, unless you count marking an entire block as "has pointers" non-conservative. The GC currently doesn't know where in a block the pointers are, so it treats all such labeled blocks conservatively.
Mar 14 2009
Sean Kelly wrote:Andrei Alexandrescu wrote:Ouch. Yet another place where introspection could help lots. Any statistics about the amount of slack memory due to false pointers would be appreciated. AndreiYou can't call delete against a struct object, so the above wouldn't compile. What may solve your problem is calling GC.hasNoPointers against the block of memory in which hugeDataStructure lives. But before that... isn't the current GC non-conservative for heap-allocated objects? I thought it's only conservative for stack objects.It's conservative for everything, unless you count marking an entire block as "has pointers" non-conservative. The GC currently doesn't know where in a block the pointers are, so it treats all such labeled blocks conservatively.
Mar 14 2009
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'sAny statistics about the amount of slack memory due to false pointers would be appreciated. AndreiThis is a corner case, but run the following code: import std.stdio, core.memory; void main() { foreach(count; 1..uint.max) { test; GC.collect; // Make it explicit to make absolutely sure GC is running. writeln(count); } } // Marked as pure to emphasize that it's not escaping someArray to anywhere, // so when test() goes out of scope, someArray is safe to GC. void test() pure { auto someArray = new uint[15_000_000]; } Disclaimer: My understanding is that this may work differently on Linux, but if you run it on Win32, it runs out of memory after about 20 iterations. I don't know about the average, but the worst cases are occasionally bad enough to make me eventually run out of 32-bit address space on stuff that should only be using ~150 megs of RAM, unless I manually delete a few large data structures. Associative arrays seem to be the worst problem because: 1. They generate a lot of false pointers. 2. They can often be large. 3. If even a few nodes don't get freed properly, they can fragment the heap severely.
Mar 14 2009
Hello dsimcha,I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like:If you can be shure ~this will get called, you might switch to malloc.
Mar 14 2009
BCS wrote:Hello dsimcha,If you do this, don't forget to register and unregister the memory with the GC if it contains any pointers into GC-allocated data. Otherwise, the GC won't see those pointers and may delete that data if there aren't any other references to it.I sometimes run into false pointer issues when using very large data structures in D. Often, these data structures are owned by a single class instance and do not escape. In these cases, is it safe to do something like:If you can be shure ~this will get called, you might switch to malloc.
Mar 14 2009