Promptly freeing the per-thread cached direct buffers when a thread exits

Tony Printezis tprintezis at
Thu Apr 5 21:45:48 UTC 2018

Hi all,

We recently hit another interesting issue with the NIO thread-local
DirectByteBuffer cache. One of our services seems to create and drop
threads at regular intervals. I assume this is due to a thread pool
dynamically resizing itself.

Let's say a thread starts, lives long enough for its Thread object to be
promoted to the old gen (along with its cached direct buffer), then exits.
This will result in its cached direct buffer(s) being unreachable in the
old gen and will only be reclaimed after the next full GC / concurrent GC

Interestingly, the service in question does concurrent GC cycles really
infrequently (one every few days) as it has a really low promotion rate.
This results in the JVM's total direct size constantly increasing (which is
effectively a native buffer leak).

Has anyone come across this issue before?

There are a few obvious ways to mitigate this, e.g., cause a Full GC /
concurrent GC cycle at regular intervals. However, the best solution IMHO
is to explicitly free any direct buffers that are still in the cache when a
thread exits.

I'll be happy to implement this and test it internally at Twitter, if it's
not on anyone else's radar. However, to do what I'm proposing I need some
sort of thread exit hook. Unfortunately, there doesn't seem to be one.

Would proposing to introduce thread exit hooks be reasonable? Or is
everyone going to freak out? :-) The hooks can be either per-Thread or even
per-ThreadLocal. And it's OK if the hooks can only be used within java.base.

FWIW, I did a simple prototype of this (I call the hooks from Thread::exit)
and it seems to work as expected.

Any thoughts / feedback on this will be very appreciated.



Tony Printezis | @TonyPrintezis | tprintezis at

More information about the core-libs-dev mailing list