Thread overview | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 27, 2014 GC for noobs | ||||
---|---|---|---|---|
| ||||
Hi, I am evaluating D for future projects and coming from C++ I find it really hard to understand semantics of destruction of GC-managed code. After many application-shutdown crashes caused by invalid order of class destructor calls I really think I need to change the way I am thinking about them (and resource management in general I suppose). My crashes (still have them and can't track all as debugging D sucks) are caused by the fact that d-tor of parent object can be called before child d-tors. Adding destroy() calls in parent d-tors helped with some of crashes but I really hate this solution as I was virtually NEVER using 'delete' in C++. I feel like I should be doing things in D very differently than I am doing them in C++. I now think I should be using structs everywhere because I understand them but I do need reference semantics (ideally with unique ownership). Please point me to a literature for C++ programmer that has very little experience with GC/resource management, because at this point I really feel like GC should be easing things and working against me. |
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szymon Gatner | On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner wrote:
> My crashes (still have them and can't track all as debugging D sucks) are caused by the fact that d-tor of parent object can be called before child d-tors. Adding destroy() calls in parent d-tors helped with some of crashes but I really hate this solution as I was virtually NEVER using 'delete' in C++.
Parent in the sense of an inheritance hierarchy or in the sense of a successor relation in a graph of objects?
In the latter case the order of destruction is undefined (IMO), i.e. if you have class A { B someB; } where B is a class as well, than B might be already destroyed if A's destructor is run.
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tobias Pankrath | On Thursday, 27 February 2014 at 09:55:14 UTC, Tobias Pankrath wrote:
> On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner wrote:
>> My crashes (still have them and can't track all as debugging D sucks) are caused by the fact that d-tor of parent object can be called before child d-tors. Adding destroy() calls in parent d-tors helped with some of crashes but I really hate this solution as I was virtually NEVER using 'delete' in C++.
Spec says:
--
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. <<
--
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tobias Pankrath | On Thursday, 27 February 2014 at 09:57:51 UTC, Tobias Pankrath wrote:
> On Thursday, 27 February 2014 at 09:55:14 UTC, Tobias Pankrath wrote:
>> On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner wrote:
>>> My crashes (still have them and can't track all as debugging D sucks) are caused by the fact that d-tor of parent object can be called before child d-tors. Adding destroy() calls in parent d-tors helped with some of crashes but I really hate this solution as I was virtually NEVER using 'delete' in C++.
>
> Spec says:
> --
> 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. <<
> --
Parent-child in the sense of object graph. I did read the spec when I started to notice crashes. I must say that it really terrified me to my very bones. I always though that higher-level memory management environments would give more and not less guarantees.
Anyway, I really need to learn how to design the code for CG and undefined d-tor calls. Any pointers would be welcome.
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szymon Gatner | Szymon Gatner wrote:
>
> Parent-child in the sense of object graph. I did read the spec when I started to notice crashes. I must say that it really terrified me to my very bones. I always though that higher-level memory management environments would give more and not less guarantees.
>
> Anyway, I really need to learn how to design the code for CG and undefined d-tor calls. Any pointers would be welcome.
I think that will depend on your use case. Why do you need to refer to child objects in your destructor?
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tobias Pankrath | On Thursday, 27 February 2014 at 10:40:15 UTC, Tobias Pankrath wrote:
> Szymon Gatner wrote:
>>
>> Parent-child in the sense of object graph. I did read the spec when I started to notice crashes. I must say that it really terrified me to my very bones. I always though that higher-level memory management environments would give more and not less guarantees.
>>
>> Anyway, I really need to learn how to design the code for CG and undefined d-tor calls. Any pointers would be welcome.
>
> I think that will depend on your use case. Why do you need to refer to child objects in your destructor?
I don't need to refer to children, I just want them to do their cleanup first as they should.
This is basic resource-management stuff, surely there has to be generic advice out there?
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szymon Gatner | Szymon Gatner:
>I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better.
Bye,
bearophile
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile wrote:
> Szymon Gatner:
>
>>I just want them to do their cleanup first as they should.
>
> Why? Perhaps if you explain what's behind your needs better, people can help better.
>
> Bye,
> bearophile
In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe.
In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members.
This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
|
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szymon Gatner | On Thursday, 27 February 2014 at 12:25:49 UTC, Szymon Gatner wrote: > On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile wrote: >> Szymon Gatner: >> >>>I just want them to do their cleanup first as they should. >> >> Why? Perhaps if you explain what's behind your needs better, people can help better. >> >> Bye, >> bearophile > > In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe. > > In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members. > > This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset. I had the same problem in Dgame. Therefore I use shared pointers (https://github.com/Dgame/Dgame/blob/master/Graphics/Surface.d#L90) or if I have to use classes, I use this: https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L44 https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L177 I put the instances in a module global array and the module dtor finalize the data. |
February 27, 2014 Re: GC for noobs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | On Thursday, 27 February 2014 at 12:32:36 UTC, Namespace wrote:
> On Thursday, 27 February 2014 at 12:25:49 UTC, Szymon Gatner wrote:
>> On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile wrote:
>>> Szymon Gatner:
>>>
>>>>I just want them to do their cleanup first as they should.
>>>
>>> Why? Perhaps if you explain what's behind your needs better, people can help better.
>>>
>>> Bye,
>>> bearophile
>>
>> In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe.
>>
>> In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members.
>>
>> This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
>
> I had the same problem in Dgame. Therefore I use shared pointers (https://github.com/Dgame/Dgame/blob/master/Graphics/Surface.d#L90) or if I have to use classes, I use this:
>
> https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L44
> https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L177
>
> I put the instances in a module global array and the module dtor finalize the data.
Module d-tor() looks like a pretty good solution, thanks. shared_ptr tho... I was really hoping that I am moving away from it to a better place...
Still, this feels like working around a language issue, if c-tor order is defined why d-tor isn't? I am ok with non-deterministic time of execution of d-tors/finalizers but not-having parent-child d-tor order defined? That is weird.
|
Copyright © 1999-2021 by the D Language Foundation