[Dlang-study] [lifetime] Safe and convenient RC arrays
Michel Fortin
michel.fortin at michelf.ca
Fri Nov 6 04:52:16 PST 2015
Marc Schütz's post with a Droppable struct gave me an idea of how arrays could work when you want them to be reference counted. So here's the idea for arrays...
First, let's use @rc as a type qualifier for arrays and strings that are reference counted. For instance, this type is a reference-counted array of int:
@rc int[]
When allocated, the array payload is allocated by requesting memory from the GC, but reserving space for a reference count before the actual content:
refcount, value1, value2, ...
So this code:
@rc int[] array = [100, 200];
// memory: 1, 100, 200
generates a special reference-counted array. The array has a length field as well as two pointers instead of one. One pointer points to the values, the other points to refcount. Here's the equivalent struct:
struct RCArray(T) {
T* ptr;
size_t length;
size_t* refcount_ptr;
}
With automatic reference counting, the reference count gets incremented when assigning to another variable:
@rc int[] array2 = array;
// memory: 2, 100, 200
So far so good. The interesting trick here happens when you assign a @rc array to a GC array: you increment refcount too:
int[] array_gc = array;
// memory: 3, 100, 200
But since it's a GC array with only one pointer, the pointer to refcount gets discarded on assignment. This means that the corresponding decrement will never happen, making sure refcount will never eventually reach zero. At this point, the only way the payload will be deallocated is when the GC scans the memory and sees the memory block as unreferenced. So that's how our array got transformed to a GC array!
>From there, you can assign back the GC array to a @rc one:
@rc int[] array3 = array_gc;
Because array_gc has no pointer to refcount, the one in array3 will be set to null. Thus, refcount is not going to be incremented or decremented here. Which is fine again, because the GC is already in charge of deallocating this array.
In the case the array never got assigned to a GC array, refcount would reach zero at some point, and the memory would be deallocated without waiting for the GC to collect.
Ok, so that's fine in theory. But in practice if you have @rc arrays like this they are almost always going to end up being owned by the GC as soon as you pass it to a function, making the refcount useless. There needs to be a way to make the GC taking ownership a rare event without forcing everyone to switch to @rc arrays. Ideas?
--
Michel Fortin
michel.fortin at michelf.ca
https://michelf.ca
More information about the Dlang-study
mailing list