More radical ideas about gc and reference counting

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Thu May 1 08:12:08 PDT 2014


On Thu, 01 May 2014 00:07:42 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> On 4/30/14, 7:20 PM, Steven Schveighoffer wrote:
>> On Wed, 30 Apr 2014 21:51:38 -0400, Andrei Alexandrescu
>> <SeeWebsiteForEmail at erdani.org> wrote:
>>
>>> On 4/30/14, 6:04 PM, Steven Schveighoffer wrote:
>>>> destructors are for cleaning up non-GC resources. File handles,  
>>>> malloc'd
>>>> memory, etc. I don't see why these need to be eliminated.
>>>
>>> Virtually all GCs are known to be horrible at managing scarce
>>> resources (including memory itself).
>>
>> The destructor can be a crutch, but it's not good to leave open
>> resources when the user of your code has not cleaned them up manually.
>
> Sounds like defensive programming to me.

Not at all. I've written programs that run for weeks at a time without  
ever crashing, who continually manage such resources via the GC.

If the GC cleans up your object, but your object wasn't finalized, you  
would have to make that a hard error. i.e. crash.

Still not talked about that I have seen, is the fact that with RC, we need  
a solution for cycles. If that's the GC then the GC WILL be cleaning up  
objects, even if they are ref counted.

>> I can see no reason to disallow destruction from cleaning up resources
>> that nobody else has managed to clean up.
>
> Make memory management faster and better for everyone. I'm not saying  
> it's reason enough, but it's a reason.

It doesn't make it better. The GC still is cleaning up the memory. Having  
it call close(fd) doesn't delay or make worse anything.

>> The largest problem with D destructors comes from trying to clean up D
>> objects in destructors of structs, that you never expected to be done
>> via the GC.
>>
>> Cleaning up files and malloc'd memory is not an issue.
>
> Not getting this...

class C
{
    private int fd = -1;
    private ubyte[] buffer;
    this(string fname) {
       fd = open(fname, O_CREAT);
       buffer = (cast(ubyte*).malloc(100))[0..100];
    }

    ~this() {
       if(fd != -1) { close(fd); fd = -1;}
       if(buffer.ptr) { .free(buffer.ptr); buffer = null}
    }
}

There is no problem with this code. It works correctly in all cases. It's  
not inefficient. It's not cumbersome or awkward or confusing. It's exactly  
what class destructors are for.

However, this *is* a problem:

class C
{
    RCValue s;
}

I have no way to say how s will be destructed, unless I poison it somehow.  
Even still, s.~this() will be called when C.~this() is done. This can be  
run in a separate thread as another object that is calling s.~this() at  
the same time.

Removing ~this() for classes just ADDS complication that we don't need.  
You are trying to fix the problem for the second situation by introducing  
a problem for the first that is unnecessary.

Solutions for the second problem are not predicated on jettisoning class  
dtors. You can, for instance, try and run the dtor for the instance of C  
in the same thread where it is owned. You could, as you say, force C into  
a ref counted mechanism. But this doesn't mean you should prevent C from  
cleaning up its resources!

Please understand that I'm not arguing for the status quo. What I'm  
arguing is that class destructors DO have some valid uses, and removing  
them would introduce new problems. I agree we need to find a solution to  
the ref counting + GC problem.

-Steve


More information about the Digitalmars-d mailing list