RFR 9: 8138696 : java.lang.ref.Cleaner - an easy to use alternative to finalization

Roger Riggs Roger.Riggs at Oracle.com
Tue Oct 6 18:05:21 UTC 2015

Hi Peter,

Thanks for the cleanup suggestions in your previous email.  I do need to 
look at the javadoc again.

On 10/6/2015 11:38 AM, Peter Levart wrote:
> On 10/06/2015 05:14 PM, Peter Levart wrote:
>> Hi Roger,
>> This looks nice. Javadocs (in particular mine) will need some work 
>> though. I agree that clear() and clean() implementations are final so 
>> that subclasses can not interfere with (de)registration. Perhaps the 
>> same could be done to isEnqueued() and enqueue() so that subclasses 
>> would not be able to pretend they can do something about those 
>> methods. I think the xxxCleanableList fields in CleanerImpl can be 
>> wildcard typed: XxxCleanableReference<?> xxxCleanableList = ... The 
>> same can be done to prev/next fields in XxxxCleanableReference 
>> classes and to local "list" variables in insert()/remove() methods. 
>> Unsafe casts and @SuppressWarnings annotations can then be removed.
>> Regards, Peter
> On a second thought: Is it really necessary to prevent access to 
> enqueue() and isEnqueued() functionality in public 
> XxxCleanableReference classes? These methods are harmless and 
> enqueue() might actually be useful in situations where one wants to 
> call it instead of clean(). The difference being that clean() does the 
> cleanup synchronously in the invoking thread while enqueue() does it 
> asynchronously in the Cleaner's thread. The only doubt I have is that 
> making isEnqueued()/enqueue() accessible forces internal 
> implementation be based based on ReferenceQueue(s), but in the future 
> it needn't be if some more performant mechanism is introduced for 
> XxxxCleanableReference(s).
I think the implementation should remain as hidden/private as possible.
Keeping the number of objects create to 1 necessitates subclassing the 
Reference types
but exposing any part/any more of their behavior breaks the encapsulation.

It is preferable that cleaning be as aggressive as possible, since it 
usually is releasing
limited resources (memory or file descriptors).  The application itself 
has other mechanisms to perform
the cleanup asynchronously if that is beneficial.  The ForkJoinPool for 

> Maybe, if asynchronous early cleanup is a desired feature, new method 
> could be added: Cleanable.cleanAsync() which would delegate to 
> super.enqueue() in current XxxxCleanableReference(s) while access to 
> isEnqueued()/enqueue() methods would still be prevented...
If it is needed, it would be cleaner to expose it deliberately with a 
new method.

Thanks, Roger

> Regards, Peter
>> On 10/06/2015 12:11 AM, Roger Riggs wrote:
>>> Hi,
>>> Building on Peter's code to provide subclassable 
>>> CleanableReferences, I rearranged
>>> the implementation a bit to make it easier to maintain.
>>> The CleanableReferences subclasses are nested inside the Cleaner to 
>>> make the scoping clear.
>>> Please review and comment:
>>> Webrev:
>>> http://cr.openjdk.java.net/~rriggs/webrev-cleaner-extensible-8138696/
>>> javadoc:
>>>   http://cr.openjdk.java.net/~rriggs/cleaner-doc2/
>>> Thanks, Roger
>>> On 10/2/2015 11:34 AM, Roger Riggs wrote:
>>>> Hi Peter,
>>>> Great comments, thanks for  looking into this...
>>>> On 10/2/2015 7:52 AM, Peter Levart wrote:
>>>>> Hi Roger,
>>>>> This is a nice and clean API. I like the trick with embedding a 
>>>>> private CleanerImpl in Cleaner and registering Cleaner itself as a 
>>>>> tracked object so that automatic thread termination can be 
>>>>> performed in a safe manner. You say the scope of this is not to 
>>>>> replace internal usages of sun.misc.Cleaner. But if they ever get 
>>>>> replaced, there are two differences between the implementations to 
>>>>> note:
>>>>> - sun.misc.Cleaner thunks get executed by a ReferenceHandler 
>>>>> thread directly and bypass ReferenceQueue-ing. This might be OK 
>>>>> for internal use, but not appropriate for public API. I doubt this 
>>>>> sun.misc.Cleaner exception in ReferenceHandler is necessary though.
>>>>> - With sun.misc.Cleaner one has to create a minimum of 2 
>>>>> additional objects per tracked object: the Cleaner object and a 
>>>>> Runnable thunk. This API requires creation of 3 objects per 
>>>>> tracked object: the Cleanup object, the internal Reference object 
>>>>> and a Runnable thunk.
>>>>> Do you think Cleaner will not be used in scenarios where this 
>>>>> additional footprint matters?
>>>> I don't have any particular data on that point.  When used with 
>>>> lambda or method references for
>>>> the thunk, it is likely there will be some binding overhead.
>>>>> It might be possible to merge the roles of Cleanup and Reference 
>>>>> into one object, like this:
>>>>> http://cr.openjdk.java.net/~plevart/jdk9-dev/Cleaner/Cleaner.java
>>>>> Making Cleanup an interface, internal Reference(s) can implement 
>>>>> it. One can cast a Cleanup instance to a Reference and invoke it's 
>>>>> other methods, but this can be prevented by throwing 
>>>>> UnsupportedOperationException from them, so nobody is tempted to 
>>>>> employ this implementation detail.
>>>> I prototyped a similar implementation but backed it out due to the 
>>>> code duplication and complexity.
>>>> It also seemed a poor choice to break the contract of Reference by 
>>>> throwing UnsupportedOperationException
>>>> on the unneeded but exposed methods since they could not be 
>>>> completely encapsulated.
>>>> It seemed cleaner to have only a concrete type that was exposed to 
>>>> the clients.
>>>> BTW, the code in you cleaner might be simpler if the cleaner lists 
>>>> for each of the three types were separate.
>>>> (The entries don't need to be intermixed).  That could simplify the 
>>>> virtual next/prev access but would still be
>>>> duplicating the linked list management code).
>>>> There could be multiple insertXXX methods so the casts were not 
>>>> necessary.
>>>>> There might be utility in exposing Cleanup (or better named 
>>>>> Cleanable) References as public abstract classes so that a 
>>>>> footprint sensitive application (for example in a data structure 
>>>>> with many elements) is possible. By subclassing such an abstract 
>>>>> reference and implementing the abstract method, a single object is 
>>>>> required per tracked object. Here I derived a proof of concept 
>>>>> from your code:
>>>>> http://cr.openjdk.java.net/~plevart/jdk9-dev/Cleaner/webrev.01/
>>>>> The simple API is unchanged and there is additional low-level API 
>>>>> that can be used if footprint matters.
>>>>> What do you think?
>>>> I see what you're getting at.  I would probably try to rearrange it 
>>>> so that only the performMethod
>>>> could be overridden.   Overriding clean() and clear() might disable 
>>>> the list management
>>>> and reduce the robustness.
>>>> I'll take another look, I was most concerned with simplicity, but 
>>>> if the overhead for the number
>>>> of the objects is a concern that can be traded off against a more 
>>>> complex implementation.
>>>> Thanks, Roger
>>>>> Regards, Peter
>>>>> On 10/01/2015 04:12 PM, Roger Riggs wrote:
>>>>>> Please review a proposal for public Cleaner API:
>>>>>> A Cleaner is proposed to provide an easy to use alternative to 
>>>>>> finalization. The service would provide easy registration and 
>>>>>> cancellation of cleanup functions for objects. Applications 
>>>>>> create a cleanup service for their own use and the service 
>>>>>> terminates when it is no longer in use.
>>>>>> Finalization has a long history of issues both in usage and 
>>>>>> performance. PhantomReferences have been proposed as the 
>>>>>> alternative GC based mechanism for cleaning functions but it has 
>>>>>> been left as an exercise to the developer to construct the 
>>>>>> necessary mechanisms to handle ReferenceQueues, handle threading 
>>>>>> issues and robust termination.
>>>>>> The Cleaner performs cleaning functions when objects are 
>>>>>> unreachable as found by garbage collection using the existing 
>>>>>> mechanisms of PhantomReference, WeakReference, SoftReferences, 
>>>>>> and ReferenceQueues. It manages a thread that dequeues references 
>>>>>> to unreachable objects and invokes the corresponding cleaning 
>>>>>> function. Registered cleaning functions can be cleared if no 
>>>>>> longer needed, can be invoked explicitly to perform the cleanup 
>>>>>> immediately, or be invoked when the object is not reachable (as 
>>>>>> detected by garbage collection) and handled by a cleanup thread.
>>>>>> The java.lang.ref package is proposed for the Cleaner because it 
>>>>>> is complementary to the reference classes and reference queues 
>>>>>> and to make it easy to find.
>>>>>> It is not a goal to replace all uses of finalization or 
>>>>>> sun.misc.Cleaner in the JDK.
>>>>>> Investigation will evaluate if and in what cases the Cleaner can 
>>>>>> replace finalization.
>>>>>> A subsequent task will examine uses of finalization and propose 
>>>>>> specific changes
>>>>>> on a case by base basis.
>>>>>> Please review and comment:
>>>>>> Javadoc:
>>>>>>   http://cr.openjdk.java.net/~rriggs/cleaner-doc/
>>>>>> Webrev:
>>>>>> http://cr.openjdk.java.net/~rriggs/webrev-cleaner-8138696/
>>>>>> Issue:
>>>>>>    https://bugs.openjdk.java.net/browse/JDK-8138696
>>>>>> Thanks, Roger

More information about the core-libs-dev mailing list