On Wed, 28 May 2025 14:27:40 GMT, Viktor Klang <vkl...@openjdk.org> wrote:

>> A ForkJoinPool can be created with worker threads that clear thread locals 
>> between tasks, thus avoiding a build up of thread locals left behind by 
>> tasks executed in the pool. The common pool does this. Erasing thread locals 
>> (by writing null to Thread.threadLocals) grinds with thread locals that keep 
>> native memory alive, esp. when there isn't a Cleaner or other means to free 
>> the memory.
>> 
>> For the JDK, this is currently an issue for the NIO direct buffer cache. If 
>> a task running on a thread in the common pool does socket or network channel 
>> I/O then it can leak when the task terminates. Prior to JDK 24 each buffer 
>> in the cache had a cleaner, as if allocated by ByteBuffer.allocateDirect, so 
>> it had some chance of being released. The changes in 
>> [JDK-8344882](https://bugs.openjdk.org/browse/JDK-8344882) mean there is no 
>> longer is cleaner for buffers in the cache.
>> 
>> The options in the short term are to restore the cleaner, register a clearer 
>> for the buffer cache, have the FJP resetThreadLocals special case 
>> "terminating thread locals", or move the terminating thread locals to a 
>> different TL map. Viktor Klang, Doug Lea, and I discussed this topic 
>> recently and agreed the best short term approach is to split the map. As 
>> terminating thread locals are for platform threads then the map can be in 
>> the Thread.FieldHolder and avoid adding another field to Thread. Medium to 
>> long term require further thought in this area, including seeing what might 
>> be useful (and safe) to expose.
>> 
>> Testing 1-5. Performance testing ongoing.
>
> src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java line 549:
> 
>> 547:     void removeCarrierThreadLocal(CarrierThreadLocal<?> local);
>> 548: 
>> 549:     /**
> 
> Copyright update?

It's already up to date so no change.

> src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java 
> line 82:
> 
>> 80:      */
>> 81:     public static void register(TerminatingThreadLocal<?> tl) {
>> 82:         if (tl != REGISTRY) {
> 
> Would this happen in any well-behaved application? If not, might be better to 
> throw an exception? 🤔

It's just a consequence of the registry being a ttl, we either check it here or 
in set, it's more local here.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/25457#discussion_r2115634840
PR Review Comment: https://git.openjdk.org/jdk/pull/25457#discussion_r2115633931

Reply via email to