8202788: Explicitly reclaim cached thread-local direct buffers at thread exit

Add internal TerminatingThreadLocal and use it to free cached thread-local direct buffers and nio-fs native buffers

Reviewed-by: tonyp, alanb
This commit is contained in:
Peter Levart 2018-06-22 17:56:55 +02:00
parent 578576f523
commit 6ec2cfcc49
8 changed files with 398 additions and 47 deletions

View file

@ -26,6 +26,7 @@
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
@ -35,9 +36,10 @@ import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
import java.io.IOException;
public class Util {
@ -50,13 +52,18 @@ public class Util {
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
// Per-thread cache of temporary direct buffers
private static ThreadLocal<BufferCache> bufferCache =
new ThreadLocal<BufferCache>()
{
private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
@Override
protected BufferCache initialValue() {
return new BufferCache();
}
@Override
protected void threadTerminated(BufferCache cache) { // will never be null
while (!cache.isEmpty()) {
ByteBuffer bb = cache.removeFirst();
free(bb);
}
}
};
/**

View file

@ -25,6 +25,7 @@
package sun.nio.fs;
import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.misc.Unsafe;
/**
@ -37,8 +38,21 @@ class NativeBuffers {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int TEMP_BUF_POOL_SIZE = 3;
private static ThreadLocal<NativeBuffer[]> threadLocal =
new ThreadLocal<NativeBuffer[]>();
private static ThreadLocal<NativeBuffer[]> threadLocal = new TerminatingThreadLocal<>() {
@Override
protected void threadTerminated(NativeBuffer[] buffers) {
// threadLocal may be initialized but with initialValue of null
if (buffers != null) {
for (int i = 0; i < TEMP_BUF_POOL_SIZE; i++) {
NativeBuffer buffer = buffers[i];
if (buffer != null) {
buffer.free();
buffers[i] = null;
}
}
}
}
};
/**
* Allocates a native buffer, of at least the given size, from the heap.