RFR: 8344332: (bf) Migrate DirectByteBuffer away from jdk.internal.ref.Cleaner [v3]
Kim Barrett
kbarrett at openjdk.org
Wed May 21 05:44:52 UTC 2025
On Wed, 21 May 2025 02:36:16 GMT, Kim Barrett <kbarrett at openjdk.org> wrote:
>> This change makes java.nio no longer use jdk.internal.ref.Cleaner to manage
>> native memory for Direct-X-Buffers. Instead it uses bespoke PhantomReferences
>> and a dedicated ReferenceQueue. This differs from PR 22165, which proposed to
>> use java.lang.ref.Cleaner.
>>
>> This change is algorithmically similar to the two previous versions:
>> JDK-6857566 and JDK-8156500 (current mainline). The critical function is
>> Bits::reserveMemory(). For both of those versions and this change, a thread
>> calls that function and tries to reserve some space. If it fails, then it
>> keeps trying until all cleaners deactivated (cleared) by prior GCs have been
>> cleaned. If reservation still fails, then it invokes the GC to try to
>> deactivate more cleaners for cleaning. After that GC it keeps trying the
>> reservation and waiting for cleaning, with sleeps to avoid a spin loop,
>> eventually either succeeding or giving up and throwing OOME.
>>
>> Retaining that algorithmic approach is one of the goals of this change, since
>> it has been successfully in use since JDK 9 (and was originally developed and
>> extensively tested in JDK 8).
>>
>> The key to this approach is having a way to determine that deactivated
>> cleaners have been cleaned. JDK-6857566 accomplished this by having waiting
>> threads help the reference processor until there was no available work.
>> JDK-8156500 waits for the reference processor to quiesce, relying on its
>> immediate processing of cleaners. java.lang.ref.Cleaner doesn't provide a way
>> to do this, which is why this change rolls its own Cleaner-like mechanism from
>> the underlying primitives. Like JDK-6857566, this change has waiting threads
>> help with cleaning references. This was a potentially undesirable feature of
>> JDK-6857566, as arbitrary allocating threads were invoking arbitrary cleaners.
>> (Though by the time of JDK-6857566 the cleaners were only used by DBB, and
>> became internal-only somewhere around that time as well.) That's not a concern
>> here, as the cleaners involved are only from DBB, and we know what they look
>> like.
>>
>> As noted in the discussion of JDK-6857566, it's good to have DBB cleaning
>> being done off the reference processing thread, as it may be expensive and
>> slow down enqueuing other pending references. JDK-6857566 only did some of
>> that, and JDK-8156500 lost that feature. This change moves all of the DBB
>> cleaning off of the reference processing thread. (So does PR 22165.)
>>
>> Neither JDK-6857566 nor this change are...
>
> Kim Barrett has updated the pull request incrementally with three additional commits since the last revision:
>
> - add description of BufferCleaner class
> - exception handling in cleaner for backward consistency
> - detabify
src/java.base/share/classes/java/nio/BufferCleaner.java line 82:
> 80: new Error("nio Cleaner terminated abnormally", x).printStackTrace();
> 81: }
> 82: System.exit(1);
This is the same behavior as jdk.internal.ref.Cleaner, for which this class is
substituting in the new regime for DBB management. PR 22165 (and earlier
versions of this PR) put this in the DBB's Deallocator::run method, but I
think it's both clearer here, and better to leave the Deallocator as it was in
mainline and be more consistent with the mainline code.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/25289#discussion_r2099400318
More information about the nio-dev
mailing list