Hi Per, Kim,

On 03/22/2016 10:24 AM, Per Liden wrote:
So, I imagine the ReferenceHandler could do something like this:

while (true) {
    // getPendingReferences() is a downcall to the VM which
    // blocks until the pending list becomes non-empty and
    // returns the whole list, transferring it to from VM-land
    // to Java-land in a safe and robust way.
    Reference<Object> pending = getPendingReferences();

    // Enqueue the references
    while (pending != null) {
        Reference<Object> r = pending;
        pending = r.discovered;
        r.discovered = null;
        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) {
            q.enqueue(r);
        }
    }
}

...so I checked what it would be needed if there was such getPendingReferences() native method. It turns out that a single native method would not be enough to support the precise direct ByteBuffer allocation. Here's a refactored webrev that introduces a getPendingReferences() method which could be turned into a native equivalent one day. There is another native method needed - int awaitEnqueuePhaseStart():

http://cr.openjdk.java.net/~plevart/jdk9-dev/removeInternalCleaner/webrev.09.part2/

The need for this additional method arises when one wants to combine reference discovery with enqueueing of discovered references into one synchronous operation (discoverAndEnqueueReferences()). A direct ByteBuffer allocating thread wants to trigger reference discovery (System.gc()) and wait for discovered references to be enqueued before continuing with direct memory reservation retries. An alternative to what I have done in above webrev would be a maintenance of a single enqueuePhase counter on the Java side with usage roughly as:

discoverAndEnqueueReferences() {
    int phase = Reference.getEnqueuePhase();
    System.gc();
    Reference.awaitEnqueuePhaseGreaterThan(phase);
}

But in that case, System.gc() would have to guarantee that after discovery of no new references, blocked getPendingReferences() would still return with an empty list of References (null) just to keep the DBB allocating thread alive. I have tried to do this variant and unfortunately it can't be reliably performed with current protocol as getPendingReferences() can only be programmed to return non-empty Reference lists without ambiguity. I created a DirectBufferAllocOOMETest to exercise situations where no new Reference(s) are discovered in a GC round.

So do what do you think - what would it be easier to support:
a) getPendingReferences() returns empty Reference list (null) after a GC round that discovers no new pending references b) getPendingReferences() returns when new Reference(s) are discovered and there is an additional int awaitEnqueuePhaseStart() as defined in above webrev.

Regards, Peter

Reply via email to