GC: memory collected but destructors not called
Steven Schveighoffer via Digitalmars-d
digitalmars-d at puremagic.com
Mon Nov 10 06:19:26 PST 2014
On 11/10/14 3:10 AM, Tomer Filiba wrote:
> The following code does not invoke S.~this. If I change `struct S` to
> `class S` - it does. Memory consumption remains constant, meaning memory
> is collected, but destructors are not called.
>
> import std.stdio;
> import std.conv;
>
> struct S {
> string s;
>
> ~this() {
> writeln("~S");
> }
> }
>
> void main() {
> auto i = 0;
> S[] arr;
>
> while (true) {
> arr ~= S("hello " ~ text(i++));
> if (arr.length == 1_000_000) {
> writeln(&arr[8888], " = ", arr[8888].s);
> arr.length = 0;
> }
> }
> }
>
>
> Is it a bug? How can I effectively implement RAII with this behavior?
Only classes call dtors from the GC. Structs do not. There are many
hairy issues with structs calling dtors from GC. Most struct dtors
expect to be called synchronously, and are not expecting to deal with
multithreading issues.
Note that structs inside classes WILL call dtors.
For example, imagine you have a struct that increments/decrements a
reference count:
struct refCounter(T)
{
T t; // assume this to be a reference type
this(T t) { t.inc();}
~this() {if(t !is null) t.dec();}
}
Of course, you would need more machinery to deal with copies, but let's
just assume that is also implemented.
You can see how this would be some kind of useful guard using RAII on
the stack.
Now, imagine you wanted to put this on the GC heap, and the GC would
call struct dtors. And let's say the program is multi-threaded. First,
the memory referred to by t isn't guaranteed to be alive, it could have
already been finalized and freed. Second, the thread that calls the
destructor may not be the thread that owns t. This means that two
threads could potentially be calling t.inc() or t.dec() at the same
time, leading to race conditions.
Note, even D's std.stdio.File is not able to deal with this properly.
> The situation is, I allocate resources for my users and return them a
> handle. I can't control what my users do with this handle, they might as
> well append it to a dynamic array/insert to AA, and remove it eventually.
> Also, the handle might be shared between several logical components, so
> it's not that one of them can explicitly finalize it.
Is the resource a GC resource? If so, don't worry about it. If not, use
a class to wrap the resource. At this point, that is all that D supports.
> Any workaround for this? Perhaps disallow certain types be allocated by
> the GC (I would actually want this feature very much)?
That would be a nice feature I think.
-Steve
More information about the Digitalmars-d
mailing list