www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Finalizing GC

reply "monarch_dodra" <monarchdodra gmail.com> writes:
Currently, the GC only finalizes classes. structs/arrays, 
allocated via the GC, are not finalized.

I don't have much experience with GC, so ...

Question: Is this the intended behavior, or is it currently only 
a limitation? WIll we ever have a GC that is capable of 
finalizing structs/arrays?

Question2: If the idea is that the GC *should* finalize, then how 
are we supposed to specify the finalizer to the GC when we 
allocate via GC.malloc ? There is apparently a 
GC.BLKAttr.FINALIZE, but how do you specify *how* to finalize...?

My "big" worry is that when we finally have a GC that can handle 
built-in array finalization, all our code that manually manages 
memory (for example: "std.array.array") will become buggy...

Thoughts? Insight?
Mar 31 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, March 31, 2013 22:15:14 monarch_dodra wrote:
 Currently, the GC only finalizes classes. structs/arrays,
 allocated via the GC, are not finalized.
 
 I don't have much experience with GC, so ...
 
 Question: Is this the intended behavior, or is it currently only
 a limitation? WIll we ever have a GC that is capable of
 finalizing structs/arrays?
 
 Question2: If the idea is that the GC *should* finalize, then how
 are we supposed to specify the finalizer to the GC when we
 allocate via GC.malloc ? There is apparently a
 GC.BLKAttr.FINALIZE, but how do you specify *how* to finalize...?
 
 My "big" worry is that when we finally have a GC that can handle
 built-in array finalization, all our code that manually manages
 memory (for example: "std.array.array") will become buggy...
 
 Thoughts? Insight?
It's my understanding that structs don't get finalized, because the type information isn't there at runtime to do it. I don't know if that can be gotten around or not, but my guess is that it's a permanent restriction unless we start putting invisible member variables in structs which have that information. I don't know though. Classes, on the other hand, hold information on their actual types at runtime, so the information is there to finalize them. But regardless, there is _no_ guarantee that _anything_ on the GC heap will ever be finalized, so any program which relies on anything on the GC heap being finalized is buggy by definition, and I don't expect that to ever change. - Jonathan M Davis
Mar 31 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Mar 31, 2013 at 06:29:21PM -0700, Jonathan M Davis wrote:
[...]
 It's my understanding that structs don't get finalized, because the
 type information isn't there at runtime to do it. I don't know if that
 can be gotten around or not, but my guess is that it's a permanent
 restriction unless we start putting invisible member variables in
 structs which have that information. I don't know though. Classes, on
 the other hand, hold information on their actual types at runtime, so
 the information is there to finalize them.
 
 But regardless, there is _no_ guarantee that _anything_ on the GC heap
 will ever be finalized, so any program which relies on anything on the
 GC heap being finalized is buggy by definition, and I don't expect
 that to ever change.
[...] So what's the point of having class dtors then?! T -- Being able to learn is a great learning; being able to unlearn is a greater learning.
Mar 31 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Sunday, 31 March 2013 at 20:15:15 UTC, monarch_dodra wrote:
 Currently, the GC only finalizes classes. structs/arrays, 
 allocated via the GC, are not finalized.

 I don't have much experience with GC, so ...

 Question: Is this the intended behavior, or is it currently 
 only a limitation? WIll we ever have a GC that is capable of 
 finalizing structs/arrays?
This is intended bahaviour. Struct objects suposed to be lightweight and map (except some cases) to C structs ABI. It would be complicated to make heap structs to be GC collectible taking into account that object can be moved without hacking current struct ABI layout.
 Question2: If the idea is that the GC *should* finalize, then 
 how are we supposed to specify the finalizer to the GC when we 
 allocate via GC.malloc ? There is apparently a 
 GC.BLKAttr.FINALIZE, but how do you specify *how* to 
 finalize...?
I didn't hear about the consensus that heap structs should be collected by GC.
 My "big" worry is that when we finally have a GC that can 
 handle built-in array finalization, all our code that manually 
 manages memory (for example: "std.array.array") will become 
 buggy...

 Thoughts? Insight?
This is even more unlikely - to break tonns of code for the sake of making heap structs collected. If you are interested in solution for this problem, then you can probably try luck in ctors/dtors/overload operators, using some reference counting algorithms or hijack context pointer of nested structs for the purpose of keeping runtime info. I doubt that it can be reliably implemented and worth using.
Mar 31 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, March 31, 2013 20:51:52 H. S. Teoh wrote:
 On Sun, Mar 31, 2013 at 06:29:21PM -0700, Jonathan M Davis wrote:
 [...]
 
 It's my understanding that structs don't get finalized, because the
 type information isn't there at runtime to do it. I don't know if that
 can be gotten around or not, but my guess is that it's a permanent
 restriction unless we start putting invisible member variables in
 structs which have that information. I don't know though. Classes, on
 the other hand, hold information on their actual types at runtime, so
 the information is there to finalize them.
 
 But regardless, there is _no_ guarantee that _anything_ on the GC heap
 will ever be finalized, so any program which relies on anything on the
 GC heap being finalized is buggy by definition, and I don't expect
 that to ever change.
[...] So what's the point of having class dtors then?!
Primarily so that non-GC resources might get cleaned up if you forget to do it manually. And it works with destroy, so if you're sure that you're done with the object, you can just call destroy on it instead of calling a clean-up function and then destroying it. But finalizers are really just a backup mechanism if you screw up. I'm not sure that I would have chosen to make it so that finalizers have no guarantee that they're going to be run, but that's what was decided. But also, in order for finalizers to be guaranteed to be run, it has to be guaranteed that the GC will collect everything before the program ends, and for whatever reason (efficiency?) it was decided that that wasn't going to be done. I believe that it's guaranteed that finalizers will run when an object is collected, but there's no guarantee that it'll ever be collected. However, I don't know what all went into those decisions, so I can't really comment on why that's what was decide. - Jonathan M Davis
Apr 01 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Apr 01, 2013 at 01:07:56AM -0700, Jonathan M Davis wrote:
 On Sunday, March 31, 2013 20:51:52 H. S. Teoh wrote:
 On Sun, Mar 31, 2013 at 06:29:21PM -0700, Jonathan M Davis wrote:
 [...]
 It's my understanding that structs don't get finalized, because
 the type information isn't there at runtime to do it. I don't know
 if that can be gotten around or not, but my guess is that it's a
 permanent restriction unless we start putting invisible member
 variables in structs which have that information. I don't know
 though. Classes, on the other hand, hold information on their
 actual types at runtime, so the information is there to finalize
 them.
 
 But regardless, there is _no_ guarantee that _anything_ on the GC
 heap will ever be finalized, so any program which relies on
 anything on the GC heap being finalized is buggy by definition,
 and I don't expect that to ever change.
[...] So what's the point of having class dtors then?!
Primarily so that non-GC resources might get cleaned up if you forget to do it manually.
But if there's no guarantee it will even run, then that completely defeats the purpose.
 And it works with destroy, so if you're sure that you're done with the
 object, you can just call destroy on it instead of calling a clean-up
 function and then destroying it. But finalizers are really just a
 backup mechanism if you screw up.
Sounds rather shaky to me. So if you screw up, then it may or may not call the dtor which may or may not clean up what needs to be cleaned up. I have a hard time swallowing that.
 I'm not sure that I would have chosen to make it so that finalizers
 have no guarantee that they're going to be run, but that's what was
 decided. But also, in order for finalizers to be guaranteed to be run,
 it has to be guaranteed that the GC will collect everything before the
 program ends, and for whatever reason (efficiency?) it was decided
 that that wasn't going to be done.
Well, it makes sense *if* there are no dtors, 'cos then it's pointless to do a GC run when the program exits: the OS will reclaim all resources anyway. But I have a hard time accepting the idea of having dtors in the first place if they only run at the whim of the runtime with no guarantees whatsoever. I thought the whole point of dtors was so that cleanup is guaranteed to be done when the object is no longer used, so that you don't have to manually clean up yourself. If you're going to have to do it manually anyway, then dtors are pointless.
 I believe that it's guaranteed that finalizers will run when an object
 is collected, but there's no guarantee that it'll ever be collected.
 However, I don't know what all went into those decisions, so I can't
 really comment on why that's what was decide.
[...] Seems to me like dtors should be removed from the language. Well, except struct dtors, which I believe do work when the struct goes out of scope? Even then, there are some nasty pitfalls in that area right now. Such as the hidden copying that happens when a struct is returned, making certain seemingly-innocuous things very unsafe. Here's an example inspired by a real-life bug that Adam Ruppe & myself ran into: struct S { int x, y, z; void delegate()[] cleanups; this(int options) { ... cleanups ~= (){ x=y=z=0; } } ~this() { // Exercise: spot the bug. foreach (c; cleanups) c(); } } So basically dtors are a minefield in D right now. They have no guarantees of running when you might expect them to, and when they *do* have predictable invocation they're subject to subtle but nasty bugs like the above. I can't say I'm very pleased with the current state of things. T -- Many open minds should be closed for repairs. -- K5 user
Apr 01 2013
prev sibling parent Leandro Motta Barros <lmb stackedboxes.org> writes:
On Mon, Apr 1, 2013 at 1:45 PM, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 On Mon, Apr 01, 2013 at 01:07:56AM -0700, Jonathan M Davis wrote:
 On Sunday, March 31, 2013 20:51:52 H. S. Teoh wrote:
 On Sun, Mar 31, 2013 at 06:29:21PM -0700, Jonathan M Davis wrote:
 [...]
Seems to me like dtors should be removed from the language. Well, except struct dtors, which I believe do work when the struct goes out of scope?
I believe that destructors are also guaranteed to be called for "scope classes" and "scope objects". Anyway, I had the same feeling when I first learned that destructors are not guaranteed to be called. I am still trying to find idioms to do proper resource management in D when trying "class-heavy" designs. BTW, I think that C# behaves similarly, so I guess these idioms do exist. ("scope" statements are great when they can be used, and RefCounted works for other cases, but they don't seem to solve all my problems.) LMB
Apr 01 2013