On 10/04/2013 03:37 PM, Aleksey Shipilev wrote:
Hi Peter,

On 10/04/2013 04:43 PM, Peter Levart wrote:
>http://cr.openjdk.java.net/~plevart/jdk8-tl/Cleaners/webrev.02/
So you are taking on assisting the ReferenceHandler directly. Nice idea.

Hi Aleksey,

I will go over your notes in a later followup. This time I present an even more refined and simple approach:

http://cr.openjdk.java.net/~plevart/jdk8-tl/Cleaners/webrev.03/

The trouble with previous approach was that while assisting ReferenceHandler thread and doing the cleaning synchronously "instead" of CleanerHandler thread (RQ.drain), the cleanersQueue was locked. If ReferenceHandler wanted to enqueue some Cleaner into cleanersQueue at that time, it would block and other Reference queueing would be impacted. So we're back to square-one when ReferenceHandler thread was processing Cleaners directly. Your approach doesn't have this problem.

So I devised another variant where we are helping ReferenceHandler but not with enqueue-ing. We're stealing Cleaners from the pending list in batches instead of going through trouble of enqueue-ing them one by one just to be able to de-queue them afterwards in the same thread. In order to prevent CleanerHandler from interfering while synchronous assistance is in progress (I really want to know when there're no more pending Cleaners - or at least when almost all of them have been processed - this is when I give-up and let Bits throw OOME), the CleanerHandler is paused by interrupting it.

Thread.sleep() can be inserted later between System.gc() and assistCleanup() if gc() happens to be asynchronous in some VM. The javadoc says the following:

/Calling the //|gc|//method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects. /

...this appears as synchronous to me and it behaves so in HotSpot. I'm just guessing, but I think that gc() triggers safepoint processing and waits for safepoint to begin. It only returns when safepoint is done and VM has already processed all references. But I don't know if that is guaranteed in all VMs.

Anyway, above variation is also predictable. I haven't been able to fail the test with any number of allocating threads.

Let me now go over your notes and see what still applies to this version...


Regards, Peter

Reply via email to