A few considerations on garbage collection

Dmitry Olshansky via Digitalmars-d digitalmars-d at puremagic.com
Wed Apr 30 11:15:03 PDT 2014


30-Apr-2014 19:33, Andrei Alexandrescu пишет:
> I'm mulling over a couple of design considerations for allocators, and
> was thinking of the following restriction:
>
> 1. No out-of-bounds tricks and no pointer arithmetic. Consider:
>
> int[] a = new int[1000];
> a = a[250 .. 750];
> int* p = a[500 .. $].ptr;
>
> Subsequently the GC should be within its rights to deallocate any memory
> within the first and last 250 integers allocated, even though in theory
> the user may get to them by using pointer arithmetic.
>
> In particular that means once a slice is shrunk, there's no growing back
> unless another slice is around.
>
> I think the current GC already does that.

It doesn't and CAN'T. As long as there is a pointer into the block it 
stays. There are plenty of ways to shoot yourself in the foot if this 
rule is not respected. Anyhow, for starters, a conservative GC doesn't 
know what is a slice when ptr/length sits in registers!

>
> 2. The same may be the case for classes WITHOUT destructors. Consider:
>
> class A
> {
>     int[1000] a;
>     int b;
>     int[1000] c;
> }
> int* p = &(new A).b;
>
> The collector should be allowed to deallocate any memory except b's own,
> even though that means the class has "holes" in it. The current GC does
> not do that.
>
> 2. However, the same shall not be the case for classes with destructors.
> Consider:
>
> class B
> {
>     int[1000] a;
>     int b;
>     int[1000] c;
>     ~this() { ... }
> }
> int* p = &(new B).b;
>
> This class has a destructor, so it will be kept around in its entirety
> if an internal pointer is held.

Does it make *anything* simpler/better? I don't see significant gains in 
any sane code.

>
> 3. Classes meant to have destructors called at collection will ALWAYS
> have been allocated with new (i.e. won't start in the middle of some
> other allocation). In other words, only class objects created with new
> will be properly collected. Those forced in odd places with emplace()
> are the responsibility of the user.
>
OK

> 4. Currently, struct objects created with new do NOT have their
> destructors called during collection. I think this may continue, meaning
> that structs created with new are somewhat low-level and are meant to be
> destroyed and deallocated manually.

IIRC they do, it's only arrays of such that doesn't. Anyhow having such 
a dangerous construct built-in (new = resource leak) in the language 
becomes questionable.

>
> 5. This brings up arrays of structs. As far as I understand, destructors
> will never be called for these, even after all references are gone:
>
> struct S { ~this() { ... } }
> auto a = new S[100];
>
> Unlike (4), arrays of structs are high-level and frequently used. I
> think we must do something about it, so I plan to support calling
> destructors for arrays of structs.

Making the point about NOT calling destructor that much more 
schizophrenic. Either do it properly or not at all.

>
> 6. The point above brings to mind more radical possibilities, such as
> making all arrays reference-counted and allowing compulsive deallocation
> when the reference counter goes down to zero.

So passing them around becomes costly, and down towards the RCslice we 
march.

> That would rule out things
> like escaping pointers to data inside arrays, which is quite extreme.

Discussions about such haven't went anywhere good. Attempts to redesign 
slices to be ref-counted soon lead to RC-ing everything.

BTW there could be sane code in the wild that may have non-reclaimable 
cycles even if ONLY array slices would become ref-counted.

> But probably worth bringing up in a brainstorming. If we disallow
> statically constructs that take addresses we may get away with it.
>
> Please chime in with your thoughts.
>
> Andrei


-- 
Dmitry Olshansky


More information about the Digitalmars-d mailing list