RFR 9: 8138696 : java.lang.ref.Cleaner - an easy to use alternative to finalization
Roger Riggs
Roger.Riggs at Oracle.com
Wed Oct 21 13:38:34 UTC 2015
Hi Peter,
I've always assumed that the arguments could not be gc'd at least until
the method returns
in part because the caller was holding references. But I suppose in a
completely inlined
case an optimizer might try to make more relaxed conclusions.
Since the new object has not yet been published, the reachability of
objects in a constructor
must have some additional rules to keep objects alive until it is published.
On 10/21/2015 8:13 AM, Peter Levart wrote:
> Not so fast, there's more...
>
> On 10/21/2015 01:50 PM, Peter Levart wrote:
>> Hi Roger,
>>
>> I think I have another race ;-)
>>
>> This time it is more theoretical than practical. If we take a look at
>> say PhantomCleanable constructor:
>>
>> public PhantomCleanable(T referent, Cleaner cleaner) {
>> super(Objects.requireNonNull(referent),
>> getCleanerImpl(cleaner).queue);
>> this.cleanerImpl = getCleanerImpl(cleaner);
>> insert();
>> }
>>
>> ...somewhere in the getCleanerImpl(cleaner) method where 'cleaner' is
>> last dereferenced and before assignment of extracted CleanerImpl to
>> this.cleanerImpl, 'cleaner' is not needed any more. If it is not
>> referenced from anywhere else in the program and JVM can prove it
>> will not be used any more, JVM is free to declare it phantom
>> reachable. The PhantomCleanable that is used to track the 'cleaner'
>> can therefore be enqueued and the cleaner thread can process it,
>> effectively emptying the 'phantomCleanableList' before this
>> PhantomCleanable constructor insert()s itself into the
>> 'phantomCleanableList'. The cleaner thread can therefore exit the
>> loop and terminate prematurely.
>>
>> The fix would be to reverse the last two statements of the
>> XxxCleanable constructor(s):
>>
>> public PhantomCleanable(T referent, Cleaner cleaner) {
>> super(Objects.requireNonNull(referent),
>> getCleanerImpl(cleaner).queue);
>> insert();
>> this.cleanerImpl = getCleanerImpl(cleaner);
Except that insert() uses cleanerImpl to know what list to insert it in.
(It could be passed as an argument; if the concern about the Cleaner
becoming phantomReachable at that moment was valid)
>> }
>>
>> ... or to add a call to the (not yet in jdk9 but coming soon)
>> reachabilityFence():
>>
>> public PhantomCleanable(T referent, Cleaner cleaner) {
>> super(Objects.requireNonNull(referent),
>> getCleanerImpl(cleaner).queue);
>> this.cleanerImpl = getCleanerImpl(cleaner);
>> insert();
>> Reference.reachabilityFence(cleaner);
>> }
>>
>
> ...similar race could be devised around the reachability of
> 'referent'. As soon as it is assigned to the Reference.referent field,
> it is not needed any more, so it can be declared
> (phantom|weakly|softly)-reachable by JVM before the XxxCleanable
> instance is insert()ed causing it to be attempted to be remove()d
> before it is insert()ed. The full fix therefore needs this:
>
> public PhantomCleanable(T referent, Cleaner cleaner) {
> super(Objects.requireNonNull(referent),
> getCleanerImpl(cleaner).queue);
> this.cleanerImpl = getCleanerImpl(cleaner);
> insert();
> Reference.reachabilityFence(cleaner);
> Reference.reachabilityFence(referent);
> }
>
Someone more familiar with the constructor/gc interactions might need to
weigh in on this.
There must be some accommodation or lots of existing code in
constructors would be/have broken.
Thanks, Roger
>
> Regards, Peter
>
>>
>> Regards, Peter
>>
>> On 10/20/2015 08:28 PM, Roger Riggs wrote:
>>> Sorry for the silence, JavaOne preparations and the availability of
>>> folks who wanted
>>> to review have stretched things out.
>>>
>>> The Cleaner API was very simple and saw feature creep as the ideas
>>> for how it might be used
>>> were explored. There are concerns about committing to supporting
>>> subclassable
>>> CleanableReferences in all future JDK versions before there had been
>>> a chance to
>>> see how if they would be useful and necessary to address the need to
>>> reduce the
>>> use of finalization within the OpenJDK and beyond.
>>>
>>> Recent updates:
>>> - The Cleaner implementation classes and the CleanableReference
>>> abstract classes are
>>> now in the jdk.internal.misc package and are available within the
>>> java.base module.
>>> - The Cleanable.clear method has been dropped; there is no current
>>> use case.
>>> Since the CleanableReferences extend Reference, clear() is
>>> available when subclassing.
>>> - The tests have been extended to cover the exported and internal APIs
>>>
>>> The Runnable thunk version is very convenient to code but does
>>> transparently create
>>> an additional object to hold the bindings.
>>> As the Cleaner is applied to the various uses of finalize we'll see
>>> how they would be used
>>> and can re-evaluate the exported API needs.
>>>
>>> Updated Javadoc:
>>> http://cr.openjdk.java.net/~rriggs/cleaner-doc/
>>>
>>> Updated Webrev:
>>> http://cr.openjdk.java.net/~rriggs/webrev-cleaner-8138696/
>>>
>>> Thanks, Roger
>>>
>>>
>>>
>>>
>>
>
More information about the core-libs-dev
mailing list