< prev index next >

src/java.base/share/classes/sun/nio/ch/Util.java

Print this page
rev 50167 : 8202788: Explicitly reclaim cached thread-local direct buffers at thread exit
Reviewed-by:


  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.nio.ch;
  27 
  28 import java.io.FileDescriptor;
  29 import java.lang.reflect.Constructor;
  30 import java.lang.reflect.InvocationTargetException;
  31 import java.nio.ByteBuffer;
  32 import java.nio.MappedByteBuffer;
  33 import java.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import java.util.Collection;
  36 import java.util.Iterator;
  37 import java.util.Set;

  38 import jdk.internal.misc.Unsafe;
  39 import sun.security.action.GetPropertyAction;
  40 import java.io.IOException;
  41 
  42 public class Util {
  43 
  44     // -- Caches --
  45 
  46     // The number of temp buffers in our pool
  47     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
  48 
  49     // The max size allowed for a cached temp buffer, in bytes
  50     private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
  51 
  52     // Per-thread cache of temporary direct buffers
  53     private static ThreadLocal<BufferCache> bufferCache =
  54         new ThreadLocal<BufferCache>()
  55     {
  56         @Override
  57         protected BufferCache initialValue() {
  58             return new BufferCache();
  59         }





  60     };
  61 
  62     /**
  63      * Returns the max size allowed for a cached temp buffers, in
  64      * bytes. It defaults to Long.MAX_VALUE. It can be set with the
  65      * jdk.nio.maxCachedBufferSize property. Even though
  66      * ByteBuffer.capacity() returns an int, we're using a long here
  67      * for potential future-proofing.
  68      */
  69     private static long getMaxCachedBufferSize() {
  70         String s = GetPropertyAction
  71                 .privilegedGetProperty("jdk.nio.maxCachedBufferSize");
  72         if (s != null) {
  73             try {
  74                 long m = Long.parseLong(s);
  75                 if (m >= 0) {
  76                     return m;
  77                 } else {
  78                     // if it's negative, ignore the system property
  79                 }


 188             } else {
 189                 int next = (start + count) % TEMP_BUF_POOL_SIZE;
 190                 buffers[next] = buf;
 191                 count++;
 192                 return true;
 193             }
 194         }
 195 
 196         boolean isEmpty() {
 197             return count == 0;
 198         }
 199 
 200         ByteBuffer removeFirst() {
 201             assert count > 0;
 202             ByteBuffer buf = buffers[start];
 203             buffers[start] = null;
 204             start = next(start);
 205             count--;
 206             return buf;
 207         }



















 208     }
 209 
 210     /**
 211      * Returns a temporary buffer of at least the given size
 212      */
 213     public static ByteBuffer getTemporaryDirectBuffer(int size) {
 214         // If a buffer of this size is too large for the cache, there
 215         // should not be a buffer in the cache that is at least as
 216         // large. So we'll just create a new one. Also, we don't have
 217         // to remove the buffer from the cache (as this method does
 218         // below) given that we won't put the new buffer in the cache.
 219         if (isBufferTooLarge(size)) {
 220             return ByteBuffer.allocateDirect(size);
 221         }
 222 
 223         BufferCache cache = bufferCache.get();
 224         ByteBuffer buf = cache.get(size);
 225         if (buf != null) {
 226             return buf;
 227         } else {




  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.nio.ch;
  27 
  28 import java.io.FileDescriptor;
  29 import java.lang.reflect.Constructor;
  30 import java.lang.reflect.InvocationTargetException;
  31 import java.nio.ByteBuffer;
  32 import java.nio.MappedByteBuffer;
  33 import java.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import java.util.Collection;
  36 import java.util.Iterator;
  37 import java.util.Set;
  38 import jdk.internal.misc.JdkThreadLocal;
  39 import jdk.internal.misc.Unsafe;
  40 import sun.security.action.GetPropertyAction;
  41 import java.io.IOException;
  42 
  43 public class Util {
  44 
  45     // -- Caches --
  46 
  47     // The number of temp buffers in our pool
  48     private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
  49 
  50     // The max size allowed for a cached temp buffer, in bytes
  51     private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
  52 
  53     // Per-thread cache of temporary direct buffers
  54     private static ThreadLocal<BufferCache> bufferCache =
  55         new JdkThreadLocal<>()
  56     {
  57         @Override
  58         protected BufferCache initialValue() {
  59             return new BufferCache();
  60         }
  61 
  62         @Override
  63         protected void threadTerminated(BufferCache cache) {
  64             cache.freeAll();
  65         }
  66     };
  67 
  68     /**
  69      * Returns the max size allowed for a cached temp buffers, in
  70      * bytes. It defaults to Long.MAX_VALUE. It can be set with the
  71      * jdk.nio.maxCachedBufferSize property. Even though
  72      * ByteBuffer.capacity() returns an int, we're using a long here
  73      * for potential future-proofing.
  74      */
  75     private static long getMaxCachedBufferSize() {
  76         String s = GetPropertyAction
  77                 .privilegedGetProperty("jdk.nio.maxCachedBufferSize");
  78         if (s != null) {
  79             try {
  80                 long m = Long.parseLong(s);
  81                 if (m >= 0) {
  82                     return m;
  83                 } else {
  84                     // if it's negative, ignore the system property
  85                 }


 194             } else {
 195                 int next = (start + count) % TEMP_BUF_POOL_SIZE;
 196                 buffers[next] = buf;
 197                 count++;
 198                 return true;
 199             }
 200         }
 201 
 202         boolean isEmpty() {
 203             return count == 0;
 204         }
 205 
 206         ByteBuffer removeFirst() {
 207             assert count > 0;
 208             ByteBuffer buf = buffers[start];
 209             buffers[start] = null;
 210             start = next(start);
 211             count--;
 212             return buf;
 213         }
 214 
 215         void freeAll() {
 216             if (isEmpty()) {
 217                 return;
 218             }
 219 
 220             for (int i = 0; i < buffers.length; i += 1) {
 221                 final ByteBuffer buf = buffers[i];
 222                 if (buf == null) {
 223                     continue;
 224                 }
 225 
 226                 free(buf);
 227                 // just in case
 228                 buffers[i] = null;
 229             }
 230             // just in case
 231             count = 0;
 232         }
 233     }
 234 
 235     /**
 236      * Returns a temporary buffer of at least the given size
 237      */
 238     public static ByteBuffer getTemporaryDirectBuffer(int size) {
 239         // If a buffer of this size is too large for the cache, there
 240         // should not be a buffer in the cache that is at least as
 241         // large. So we'll just create a new one. Also, we don't have
 242         // to remove the buffer from the cache (as this method does
 243         // below) given that we won't put the new buffer in the cache.
 244         if (isBufferTooLarge(size)) {
 245             return ByteBuffer.allocateDirect(size);
 246         }
 247 
 248         BufferCache cache = bufferCache.get();
 249         ByteBuffer buf = cache.get(size);
 250         if (buf != null) {
 251             return buf;
 252         } else {


< prev index next >