digitalmars.D - GC does not delete subclass
- Matthias Thurau (40/40) Dec 17 2007 Hi,
- Matthias Thurau (23/23) Dec 17 2007 BTW:
- Jason House (2/3) Dec 17 2007 It looks like a bug to me. Does this happen with Phobos or Tango? (or ...
- Sean Kelly (6/12) Dec 17 2007 I've noticed that the most recent object to be constructed is often not
- Matthias Thurau (3/3) Dec 18 2007 thanks for replys...
- Lars Ivar Igesund (8/14) Dec 18 2007 It is hardly a bug. You should in any case not depend on an object being
- 0ffh (4/7) Dec 18 2007 Ignore it. Most probably no bug!
- Jason House (3/10) Dec 18 2007 I don't think it was specifically the order but rather full collection n...
- Steven Schveighoffer (11/25) Dec 18 2007 Custom destructors should NEVER destroy other GC allocated objects. the...
- Matthias Thurau (2/2) Dec 18 2007 "If the objects are no longer referenced, the GC will destroy those also...
- Regan Heath (9/12) Dec 18 2007 I imagine Sean was correct when he said:
- 0ffh (7/16) Dec 18 2007 Given that Sean is correct (which is plausible), then it is incorrect to
- Steven Schveighoffer (19/22) Dec 18 2007 My understanding of scope is that the object is supposed to be forcefull...
- Sean Kelly (20/44) Dec 18 2007 I'm pretty sure that this is what's happening. However, it is only
- Steven Schveighoffer (7/26) Dec 18 2007 Oh! I misunderstood the original post.
- Sean Kelly (8/11) Dec 18 2007 Technically, it is. It's just not destroying it in the collection
- Gide Nwawudu (5/16) Dec 18 2007 To help the GC, is Java-like null assignment necessary? The following
- Sean Kelly (9/30) Dec 18 2007 Not usually. The problem is this case is a register with the value, not...
- Matthias Thurau (4/4) Dec 19 2007 "The problem is this case is a register with the value, not
- guslay (20/26) Dec 19 2007 A register is a small storage available to the cpu to make computation. ...
- Sean Kelly (8/27) Dec 19 2007 Oops. My comment about registers referred to the GC not collecting the
- Jason House (2/18) Dec 19 2007 I think that the point of the original post is getting lost. After havi...
- Sean Kelly (3/23) Dec 19 2007 Right. This related to my comment about registers above.
- Jason House (2/18) Dec 18 2007 I wasn't asking about necessary. I was asking if it's valid. It's easy...
- Steven Schveighoffer (11/37) Dec 18 2007 Not neccessary == not implemented :) Why implement a feature that is no...
Hi, I just made some small examples for myself to understand the GC. Here i have a testcase, that has an unexpected behavior for me: import std.stdio; static int number = 0; static int number2 = 0; class MyClass { public: this() { writefln("Constructor %d", number); myNumber = number; number++; member = new My2Class(); }; ~this() { writefln("Destructor %d", myNumber); }; My2Class member; int myNumber; }; class My2Class { public: this() { writefln("Sub_Constructor2 %d", number2); myNumber2 = number2; number2++; }; ~this() { writefln("Sub_Destructor2 %d", myNumber2); }; int myNumber2; }; int main(char[][] args) { { scope MyClass A = new MyClass(); } std.gc.fullCollect(); writefln("The Sub Class from 0 does not get deleted yet!"); MyClass C = new MyClass(); return 0; }; The Output ist: Constructor 0 Sub_Constructor2 0 Destructor 0 The Sub Class from 0 does not get deleted yet! Constructor 1 Sub_Constructor2 1 Sub_Destructor2 1 Destructor 1 Sub_Destructor2 0
Dec 17 2007
BTW: This is working correctly: void func() { MyClass A = new MyClass(); }; int main(char[][] args) { func(); std.gc.fullCollect(); writefln("The Sub Class from 0 does not get deleted yet!"); MyClass C = new MyClass(); return 0; }; When i put the "scope" into the func(), then i get the output from above again. The right ouput was in my opinion: Constructor 0 Sub_Constructor2 0 Sub_Destructor2 0 Destructor 0 The Sub Class from 0 does not get deleted yet! Constructor 1 Sub_Constructor2 1 Sub_Destructor2 1 Destructor 1
Dec 17 2007
Matthias Thurau Wrote:When i put the "scope" into the func(), then i get the output from above again.It looks like a bug to me. Does this happen with Phobos or Tango? (or both?) I know they use different gc's.
Dec 17 2007
Jason House wrote:Matthias Thurau Wrote:I've noticed that the most recent object to be constructed is often not deleted in simple test cases. My guess is that a reference to this address is probably still lingering in a register somewhere, so the GC thinks it's still alive. This happens in Phobos and Tango. SeanWhen i put the "scope" into the func(), then i get the output from above again.It looks like a bug to me. Does this happen with Phobos or Tango? (or both?) I know they use different gc's.
Dec 17 2007
thanks for replys... So how do i handle this? Should i ignore that or am i doing something wrong? (Ist it a bug or not? :) bye
Dec 18 2007
Matthias Thurau wrote:thanks for replys... So how do i handle this? Should i ignore that or am i doing something wrong? (Ist it a bug or not? :) byeIt is hardly a bug. You should in any case not depend on an object being collected. Garbage collection is not deterministic. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Dec 18 2007
Matthias Thurau wrote:thanks for replys... So how do i handle this? Should i ignore that or am i doing something wrong? (Ist it a bug or not? :)Ignore it. Most probably no bug! Who has ever claimed that the GC collects objects in any specific order? regards, frank
Dec 18 2007
0ffh Wrote:Matthias Thurau wrote:I don't think it was specifically the order but rather full collection not fully collecting. I haven't tried this, but is it possible to declare class member variables as scope so that they will get deleted when the rest of the object does? This could save coding of custom destructors in some cases.thanks for replys... So how do i handle this? Should i ignore that or am i doing something wrong? (Ist it a bug or not? :)Ignore it. Most probably no bug! Who has ever claimed that the GC collects objects in any specific order?
Dec 18 2007
"Jason House" wrote0ffh Wrote:Custom destructors should NEVER destroy other GC allocated objects. the GC cannot guarantee the order of collection, meaning if you have a pointer to another GC allocated object, that object may have already been collected. There is no real reason to delete other objects in a destructor. If the objects are no longer referenced, the GC will destroy those also. The only things you should destroy in a destructor are non-GC allocated resources, such as file descriptors, or memory allocated with C's malloc. So to answer your question: scope is not necessary as a modifier for a member variable. -SteveMatthias Thurau wrote:I don't think it was specifically the order but rather full collection not fully collecting. I haven't tried this, but is it possible to declare class member variables as scope so that they will get deleted when the rest of the object does? This could save coding of custom destructors in some cases.thanks for replys... So how do i handle this? Should i ignore that or am i doing something wrong? (Ist it a bug or not? :)Ignore it. Most probably no bug! Who has ever claimed that the GC collects objects in any specific order?
Dec 18 2007
"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.
Dec 18 2007
Matthias Thurau wrote:"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.I imagine Sean was correct when he said: "I've noticed that the most recent object to be constructed is often not deleted in simple test cases. My guess is that a reference to this address is probably still lingering in a register somewhere, so the GC thinks it's still alive. This happens in Phobos and Tango." In which case, yes, there is a 'bug' in full collect. Post a bug report, if one does not already exist. :) Regan
Dec 18 2007
Regan Heath wrote:I imagine Sean was correct when he said: "I've noticed that the most recent object to be constructed is often not deleted in simple test cases. My guess is that a reference to this address is probably still lingering in a register somewhere, so the GC thinks it's still alive. This happens in Phobos and Tango." In which case, yes, there is a 'bug' in full collect. Post a bug report, if one does not already exist. :)Given that Sean is correct (which is plausible), then it is incorrect to speak of a bug (or even a 'bug'). The algorithm works as specified. If someone does not like (or understand) the specification you can hardly (actually, not even remotely) speak of a bug. Sorry for nitpicking, but this is bothering me. regards, frank
Dec 18 2007
"Matthias Thurau" wrote"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.My understanding of scope is that the object is supposed to be forcefully deleted at the end of the scope (not through the GC). So in your case, I believe there is a bug, because delete should call the destructor immediately. i.e.: { scope C = new C; } should be equivalent to: { auto C = new C; delete C; } So I believe that the GC shouldn't be calling the destructor in fullcollect, it should be called BEFORE fullcollect is called. Of course, I may be misunderstanding how scope works :) With regards to my response, I just wanted to point out to Jason that destructors should not be used as he was alluding to. -Steve
Dec 18 2007
Steven Schveighoffer wrote:"Matthias Thurau" wroteI'm pretty sure that this is what's happening. However, it is only deleting C, not the objects that C points to. This is necessary behavior. Consider: class A {} class B { this( A a ) { val = a; } A val; } void fn( A val ) { scope B = new B( val ); } You certainly wouldn't want the instance of A deleted when fn exits as well. Sean"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.My understanding of scope is that the object is supposed to be forcefully deleted at the end of the scope (not through the GC). So in your case, I believe there is a bug, because delete should call the destructor immediately. i.e.: { scope C = new C; } should be equivalent to: { auto C = new C; delete C; } So I believe that the GC shouldn't be calling the destructor in fullcollect, it should be called BEFORE fullcollect is called.
Dec 18 2007
"Sean Kelly" wroteI'm pretty sure that this is what's happening. However, it is only deleting C, not the objects that C points to. This is necessary behavior. Consider: class A {} class B { this( A a ) { val = a; } A val; } void fn( A val ) { scope B = new B( val ); } You certainly wouldn't want the instance of A deleted when fn exits as well.Oh! I misunderstood the original post. Yes, I agree that the current behavior should be the expected behavior for the original example. I thought that for some reason the destructor of the scoped class was not getting called when the scope exited. -Steve
Dec 18 2007
Matthias Thurau wrote:"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.Technically, it is. It's just not destroying it in the collection immediately following the object's allocation, which isn't guaranteed anyway. As I said previously, it's likely that a register still holds the address of this object when the allocation is triggered, because basically nothing happens between the object's construction and the collection. In a real application, such things are unlikely occur. Sean
Dec 18 2007
On Tue, 18 Dec 2007 11:45:49 -0800, Sean Kelly <sean f4.ca> wrote:Matthias Thurau wrote:"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.Technically, it is. It's just not destroying it in the collection immediately following the object's allocation, which isn't guaranteed anyway. As I said previously, it's likely that a register still holds the address of this object when the allocation is triggered, because basically nothing happens between the object's construction and the collection. In a real application, such things are unlikely occur.~this() { writefln("Destructor %d", myNumber); }To help the GC, is Java-like null assignment necessary? The following line helps std.gc.fullCollect() to destroy My2Class members. ~this() { writefln("Destructor %d", myNumber); member = null; } Gide
Dec 18 2007
Gide Nwawudu wrote:On Tue, 18 Dec 2007 11:45:49 -0800, Sean Kelly <sean f4.ca> wrote:Not usually. The problem is this case is a register with the value, not a memory location. I've run into it before when trying to create simple unit tests and demos in D. The easiest way around it that I've found is to construct an additional "throw away" object after the object you expect to be cleaned up, to overwrite any lingering register data that may still point to the old object. This is handy for tiny test apps, but again, I don't think anything needs to be done for real apps. SeanMatthias Thurau wrote:"If the objects are no longer referenced, the GC will destroy those also." Thats exact the case: In my example the GC isn t destroying that unreferenced member.Technically, it is. It's just not destroying it in the collection immediately following the object's allocation, which isn't guaranteed anyway. As I said previously, it's likely that a register still holds the address of this object when the allocation is triggered, because basically nothing happens between the object's construction and the collection. In a real application, such things are unlikely occur.~this() { writefln("Destructor %d", myNumber); }To help the GC, is Java-like null assignment necessary? The following line helps std.gc.fullCollect() to destroy My2Class members. ~this() { writefln("Destructor %d", myNumber); member = null; }
Dec 18 2007
"The problem is this case is a register with the value, not a memory location" I don t understand what a register is :( Could you give me an example? And maybe Your workaround for that? greetings
Dec 19 2007
Matthias Thurau Wrote:"The problem is this case is a register with the value, not a memory location" I don t understand what a register is :( Could you give me an example? And maybe Your workaround for that? greetingsA register is a small storage available to the cpu to make computation. http://en.wikipedia.org/wiki/Processor_register However I doubt that Sean's assumption is valid in this case. I've modified the original testcase to call { MyClass A = new MyClass(); } up to a couple tens of THOUSAND times. Whereas the scoped class is destroyed on scope exit, the destructor of the embedded object is only called at program termination (as described). Collect as no effect on them, no matter how many instances are created. That would be a lot of registers! Some other things I have noticed: * Without scope attribute, all instances of both classes are destroyed on collect. No problem. * With the scope attribute, embedded instances are destroyed in reverse order of creation, by group of 256. Sub_Destructor2 255 ... Sub_Destructor2 0 Sub_Destructor2 511 ... Sub_Destructor2 256 .. This GC behavior is stranger than usual... (using Phobos.)
Dec 19 2007
guslay wrote:Matthias Thurau Wrote:Oops. My comment about registers referred to the GC not collecting the most recently constructed object which simply went out of scope. Objects created with the "scope" attribute are entirely different. In that case, the "scope" object is deleted when scope exits, but no objects it references are deleted. This is by design, and I addressed it in another post in this thread. Sean"The problem is this case is a register with the value, not a memory location" I don t understand what a register is :( Could you give me an example? And maybe Your workaround for that? greetingsA register is a small storage available to the cpu to make computation. http://en.wikipedia.org/wiki/Processor_register However I doubt that Sean's assumption is valid in this case. I've modified the original testcase to call { MyClass A = new MyClass(); } up to a couple tens of THOUSAND times. Whereas the scoped class is destroyed on scope exit, the destructor of the embedded object is only called at program termination (as described). Collect as no effect on them, no matter how many instances are created.
Dec 19 2007
Sean Kelly Wrote:guslay wrote:I think that the point of the original post is getting lost. After having scope variable(s) go out of focus (and get deallocated), a call to full collect is done. The issue was that full collect did not collect the objects allocated by the scope objects, even though there was no references to them.However I doubt that Sean's assumption is valid in this case. I've modified the original testcase to call { MyClass A = new MyClass(); } up to a couple tens of THOUSAND times. Whereas the scoped class is destroyed on scope exit, the destructor of the embedded object is only called at program termination (as described). Collect as no effect on them, no matter how many instances are created.Oops. My comment about registers referred to the GC not collecting the most recently constructed object which simply went out of scope. Objects created with the "scope" attribute are entirely different. In that case, the "scope" object is deleted when scope exits, but no objects it references are deleted. This is by design, and I addressed it in another post in this thread.
Dec 19 2007
Jason House wrote:Sean Kelly Wrote:Right. This related to my comment about registers above. Seanguslay wrote:I think that the point of the original post is getting lost. After having scope variable(s) go out of focus (and get deallocated), a call to full collect is done. The issue was that full collect did not collect the objects allocated by the scope objects, even though there was no references to them.However I doubt that Sean's assumption is valid in this case. I've modified the original testcase to call { MyClass A = new MyClass(); } up to a couple tens of THOUSAND times. Whereas the scoped class is destroyed on scope exit, the destructor of the embedded object is only called at program termination (as described). Collect as no effect on them, no matter how many instances are created.Oops. My comment about registers referred to the GC not collecting the most recently constructed object which simply went out of scope. Objects created with the "scope" attribute are entirely different. In that case, the "scope" object is deleted when scope exits, but no objects it references are deleted. This is by design, and I addressed it in another post in this thread.
Dec 19 2007
Steven Schveighoffer Wrote:"Jason House" wroteI wasn't asking about necessary. I was asking if it's valid. It's easy enough to construct RAII-like examples where a timely destruction of a member variable would be handy. It can also be handy when standard GC operation is overridden.I haven't tried this, but is it possible to declare class member variables as scope so that they will get deleted when the rest of the object does? This could save coding of custom destructors in some cases.Custom destructors should NEVER destroy other GC allocated objects. the GC cannot guarantee the order of collection, meaning if you have a pointer to another GC allocated object, that object may have already been collected. There is no real reason to delete other objects in a destructor. If the objects are no longer referenced, the GC will destroy those also. The only things you should destroy in a destructor are non-GC allocated resources, such as file descriptors, or memory allocated with C's malloc. So to answer your question: scope is not necessary as a modifier for a member variable.
Dec 18 2007
"Jason House" wroteSteven Schveighoffer Wrote:Not neccessary == not implemented :) Why implement a feature that is not needed? I guess I should have stated that. From the attributes page (http://www.digitalmars.com/d/attribute.html): "scope cannot be applied to globals, statics, data members, ref or out parameters." Timely destruction of a member that is not referenced in any other object/thread should occur when the object that owns the member is destroyed. No need to force it, which is why scope isn't necessary or valid. -Steve"Jason House" wroteI wasn't asking about necessary. I was asking if it's valid. It's easy enough to construct RAII-like examples where a timely destruction of a member variable would be handy. It can also be handy when standard GC operation is overridden.I haven't tried this, but is it possible to declare class member variables as scope so that they will get deleted when the rest of the object does? This could save coding of custom destructors in some cases.Custom destructors should NEVER destroy other GC allocated objects. the GC cannot guarantee the order of collection, meaning if you have a pointer to another GC allocated object, that object may have already been collected. There is no real reason to delete other objects in a destructor. If the objects are no longer referenced, the GC will destroy those also. The only things you should destroy in a destructor are non-GC allocated resources, such as file descriptors, or memory allocated with C's malloc. So to answer your question: scope is not necessary as a modifier for a member variable.
Dec 18 2007