View mode: basic / threaded / horizontal-split · Log in · Help
October 13, 2012
RFC: Pinning interface for the GC
Hi,

With precise garbage collection coming up, and most likely compacting 
garbage collection in the future, I think it's time we start thinking 
about an API to pin garbage collector-managed objects.

A typical approach that people use to 'pin' objects today is to allocate 
a chunk of memory from the C heap, add it as a root [range], and store a 
reference in it. That, or just global variables.

This is kind of terrible because adding the chunk of memory as a root 
forces the GC to actually scan it, which is unnecessary when what you 
really want is to pin the object in place and tell the GC "I know what 
I'm doing, don't touch this".

I propose the following functions in core.memory.GC:

    static bool pin(const(void)* p) nothrow;
    static bool unpin(const(void)* p) nothrow;

The pin function shall pin the object pointed to by p in place such that 
it is not allowed to be moved nor collected until unpinned. The function 
shall return true if the object was successfully pinned or false if the 
object was already pinned or didn't belong to the garbage collector in 
the first place.

The unpin function shall unpin the object pointed to by p such that it 
is once again eligible for moving and collection as usual. The function 
shall return true if the object was successfully unpinned or false if 
the object was not pinned or didn't belong to the garbage collector in 
the first place.

Destroy!

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
October 13, 2012
Re: RFC: Pinning interface for the GC
On Saturday, 13 October 2012 at 18:58:27 UTC, Alex Rønne 
Petersen wrote:
> This is kind of terrible because adding the chunk of memory as 
> a root forces the GC to actually scan it, which is unnecessary 
> when what you really want is to pin the object in place and 
> tell the GC "I know what I'm doing, don't touch this".

If pointers in pinned objects make their targets live, there 
would be no difference to simply adding the object as a root. So 
in your proposal, pinned objects are implicitly marked live if 
they aren't reachable from any of the roots, but any other 
objects reachable only from a pinned object but not from a root 
would be collected – correct?

David
October 13, 2012
Re: RFC: Pinning interface for the GC
On 13-10-2012 21:24, David Nadlinger wrote:
> On Saturday, 13 October 2012 at 18:58:27 UTC, Alex Rønne Petersen wrote:
>> This is kind of terrible because adding the chunk of memory as a root
>> forces the GC to actually scan it, which is unnecessary when what you
>> really want is to pin the object in place and tell the GC "I know what
>> I'm doing, don't touch this".
>
> If pointers in pinned objects make their targets live, there would be no
> difference to simply adding the object as a root. So in your proposal,
> pinned objects are implicitly marked live if they aren't reachable from
> any of the roots, but any other objects reachable only from a pinned
> object but not from a root would be collected – correct?
>
> David

There is a difference: Adding the object itself as a root does not 
actually guarantee that the object *itself* might not be collected. At 
least, this is how I have to assume things work given that this is not 
guaranteed here: http://dlang.org/phobos/core_memory.html#addRoot

As for your question: Not quite. A pinned object that points to any 
other unpinned objects will implicitly keep those alive. This is at 
least how I would expect it to work, following the principle of least 
surprise.

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
October 13, 2012
Re: RFC: Pinning interface for the GC
On Saturday, 13 October 2012 at 19:34:29 UTC, Alex Rønne 
Petersen wrote:
> As for your question: Not quite. A pinned object that points to 
> any other unpinned objects will implicitly keep those alive. 
> This is at least how I would expect it to work, following the 
> principle of least surprise.

But then the GC _does_ have to scan those objects to be able to 
mark the whole graph as live, no? Wasn't it this what you were 
referring to as "kind of terrible" in your first post?

But yes, for a moving GC, a way to pin objects would have to be 
added, and lots of code using GC.add*() for interfacing with C 
would have to be changed – or we make those functions actually 
pin the objects for backwards compatibility and add a new set of 
functions which really just add something as a root.

David
October 13, 2012
Re: RFC: Pinning interface for the GC
On Saturday, 13 October 2012 at 19:34:29 UTC, Alex Rønne 
Petersen wrote:
> There is a difference: Adding the object itself as a root does 
> not actually guarantee that the object *itself* might not be 
> collected. At least, this is how I have to assume things work 
> given that this is not guaranteed here: 
> http://dlang.org/phobos/core_memory.html#addRoot

Actually, it does: the internal array of added roots is simply 
considered an additional range to be scanned by the GC 
implementation. The docs should probably be clarified in this 
regard.

David
October 13, 2012
Re: RFC: Pinning interface for the GC
On 13-10-2012 21:51, David Nadlinger wrote:
> On Saturday, 13 October 2012 at 19:34:29 UTC, Alex Rønne Petersen wrote:
>> As for your question: Not quite. A pinned object that points to any
>> other unpinned objects will implicitly keep those alive. This is at
>> least how I would expect it to work, following the principle of least
>> surprise.
>
> But then the GC _does_ have to scan those objects to be able to mark the
> whole graph as live, no? Wasn't it this what you were referring to as
> "kind of terrible" in your first post?

Ah, I could have been clearer here.

The problem with using roots is two-fold:

1) It adds unnecessary work for the marking phase.
2) It forces scanning of 'pinned' objects to be imprecise.

(1) is not so much of a problem (it only happens if you have root ranges 
with null pointers and so on), but (2) can be.

Another problem that would pop up if we made scanning of roots precise 
is that, then, the stored reference could be moved (as you also pointed 
out).

I guess there is also the issue of adding roots being a relatively 
expensive operation - it has to go through a mutex-guarded function 
whereas pinning objects can be made lock-free (at least on some 
architectures).

I think the problem boils down to using roots for something they're not 
meant to be used for, semantically.

>
> But yes, for a moving GC, a way to pin objects would have to be added,
> and lots of code using GC.add*() for interfacing with C would have to be
> changed – or we make those functions actually pin the objects for
> backwards compatibility and add a new set of functions which really just
> add something as a root.
>
> David

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
October 13, 2012
Re: RFC: Pinning interface for the GC
On Saturday, 13 October 2012 at 20:00:54 UTC, David Nadlinger 
wrote:
> Actually, it does: the internal array of added roots is simply 
> considered an additional range to be scanned by the GC 
> implementation. The docs should probably be clarified in this 
> regard.

https://github.com/D-Programming-Language/druntime/pull/322

David
October 13, 2012
Re: RFC: Pinning interface for the GC
On 13-10-2012 22:00, David Nadlinger wrote:
> On Saturday, 13 October 2012 at 19:34:29 UTC, Alex Rønne Petersen wrote:
>> There is a difference: Adding the object itself as a root does not
>> actually guarantee that the object *itself* might not be collected. At
>> least, this is how I have to assume things work given that this is not
>> guaranteed here: http://dlang.org/phobos/core_memory.html#addRoot
>
> Actually, it does: the internal array of added roots is simply
> considered an additional range to be scanned by the GC implementation.
> The docs should probably be clarified in this regard.
>
> David

That's good to know.

I'm not convinced that this should be defined behavior though. It 
encourages semantically incorrect use of the API (see my other reply).

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
October 13, 2012
Re: RFC: Pinning interface for the GC
On Saturday, 13 October 2012 at 20:12:04 UTC, Alex Rønne 
Petersen wrote:
> 2) It forces scanning of 'pinned' objects to be imprecise.

I'm not so sure about that.

In the comment section you added to Git core.memory, you wrote 
»Roots are always scanned conservatively. Roots include […] 
memory locations added through the GC.addRoot and GC.addRange 
functions.«. But this statement is problematic, since addRange() 
adds a »memory location« consisting of root pointers, whereas 
addRoot() adds a single (rvalue) root pointer.

Thus, depending on which case you consider, »memory location« 
would refer to different levels of indirection.

As far as I can see, adding objects you want to »pin« as roots 
would only force them to be scanned imprecisely if you'd force 
the entire GC memory block referred to by addRoot() resp. all the 
GC blocks referred to by the range added using addRange() to be 
scanned conservatively. But why would this be necessary?

David
October 14, 2012
Re: RFC: Pinning interface for the GC
We already have a NO_MOVE attribute that can be set or unset.  
What's wrong with that?

http://dlang.org/phobos/core_memory.html#NO_MOVE

On Saturday, 13 October 2012 at 18:58:27 UTC, Alex Rønne 
Petersen wrote:
> Hi,
>
> With precise garbage collection coming up, and most likely 
> compacting garbage collection in the future, I think it's time 
> we start thinking about an API to pin garbage collector-managed 
> objects.
>
> A typical approach that people use to 'pin' objects today is to 
> allocate a chunk of memory from the C heap, add it as a root 
> [range], and store a reference in it. That, or just global 
> variables.
>
> This is kind of terrible because adding the chunk of memory as 
> a root forces the GC to actually scan it, which is unnecessary 
> when what you really want is to pin the object in place and 
> tell the GC "I know what I'm doing, don't touch this".
>
> I propose the following functions in core.memory.GC:
>
>     static bool pin(const(void)* p) nothrow;
>     static bool unpin(const(void)* p) nothrow;
>
> The pin function shall pin the object pointed to by p in place 
> such that it is not allowed to be moved nor collected until 
> unpinned. The function shall return true if the object was 
> successfully pinned or false if the object was already pinned 
> or didn't belong to the garbage collector in the first place.
>
> The unpin function shall unpin the object pointed to by p such 
> that it is once again eligible for moving and collection as 
> usual. The function shall return true if the object was 
> successfully unpinned or false if the object was not pinned or 
> didn't belong to the garbage collector in the first place.
>
> Destroy!
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home