1 /*
   2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  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 java.nio;
  27 
  28 import jdk.internal.access.JavaLangRefAccess;
  29 import jdk.internal.access.SharedSecrets;
  30 import jdk.internal.misc.Unsafe;
  31 import jdk.internal.misc.VM;
  32 import jdk.internal.misc.VM.BufferPool;
  33 
  34 import java.util.concurrent.atomic.AtomicLong;
  35 
  36 /**
  37  * Access to bits, native and otherwise.
  38  */
  39 
  40 class Bits {                            // package-private
  41 
  42     private Bits() { }
  43 
  44 
  45     // -- Swapping --
  46 
  47     static short swap(short x) {
  48         return Short.reverseBytes(x);
  49     }
  50 
  51     static char swap(char x) {
  52         return Character.reverseBytes(x);
  53     }
  54 
  55     static int swap(int x) {
  56         return Integer.reverseBytes(x);
  57     }
  58 
  59     static long swap(long x) {
  60         return Long.reverseBytes(x);
  61     }
  62 
  63 
  64     // -- Unsafe access --
  65 
  66     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  67 
  68     // -- Processor and memory-system properties --
  69 
  70     private static int PAGE_SIZE = -1;
  71 
  72     static int pageSize() {
  73         if (PAGE_SIZE == -1)
  74             PAGE_SIZE = UNSAFE.pageSize();
  75         return PAGE_SIZE;
  76     }
  77 
  78     static int pageCount(long size) {
  79         return (int)(size + (long)pageSize() - 1L) / pageSize();
  80     }
  81 
  82     private static boolean UNALIGNED = UNSAFE.unalignedAccess();
  83 
  84     static boolean unaligned() {
  85         return UNALIGNED;
  86     }
  87 
  88 
  89     // -- Direct memory management --
  90 
  91     // A user-settable upper limit on the maximum amount of allocatable
  92     // direct buffer memory.  This value may be changed during VM
  93     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
  94     private static volatile long MAX_MEMORY = VM.maxDirectMemory();
  95     private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
  96     private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
  97     private static final AtomicLong COUNT = new AtomicLong();
  98     private static volatile boolean MEMORY_LIMIT_SET;
  99 
 100     // max. number of sleeps during try-reserving with exponentially
 101     // increasing delay before throwing OutOfMemoryError:
 102     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
 103     // which means that OOME will be thrown after 0.5 s of trying
 104     private static final int MAX_SLEEPS = 9;
 105 
 106     // These methods should be called whenever direct memory is allocated or
 107     // freed.  They allow the user to control the amount of direct memory
 108     // which a process may access.  All sizes are specified in bytes.
 109     static void reserveMemory(long size, int cap) {
 110 
 111         if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
 112             MAX_MEMORY = VM.maxDirectMemory();
 113             MEMORY_LIMIT_SET = true;
 114         }
 115 
 116         // optimist!
 117         if (tryReserveMemory(size, cap)) {
 118             return;
 119         }
 120 
 121         final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 122         boolean interrupted = false;
 123         try {
 124 
 125             // Retry allocation until success or there are no more
 126             // references (including Cleaners that might free direct
 127             // buffer memory) to process and allocation still fails.
 128             boolean refprocActive;
 129             do {
 130                 try {
 131                     refprocActive = jlra.waitForReferenceProcessing();
 132                 } catch (InterruptedException e) {
 133                     // Defer interrupts and keep trying.
 134                     interrupted = true;
 135                     refprocActive = true;
 136                 }
 137                 if (tryReserveMemory(size, cap)) {
 138                     return;
 139                 }
 140             } while (refprocActive);
 141 
 142             // trigger VM's Reference processing
 143             System.gc();
 144 
 145             // A retry loop with exponential back-off delays.
 146             // Sometimes it would suffice to give up once reference
 147             // processing is complete.  But if there are many threads
 148             // competing for memory, this gives more opportunities for
 149             // any given thread to make progress.  In particular, this
 150             // seems to be enough for a stress test like
 151             // DirectBufferAllocTest to (usually) succeed, while
 152             // without it that test likely fails.  Since failure here
 153             // ends in OOME, there's no need to hurry.
 154             long sleepTime = 1;
 155             int sleeps = 0;
 156             while (true) {
 157                 if (tryReserveMemory(size, cap)) {
 158                     return;
 159                 }
 160                 if (sleeps >= MAX_SLEEPS) {
 161                     break;
 162                 }
 163                 try {
 164                     if (!jlra.waitForReferenceProcessing()) {
 165                         Thread.sleep(sleepTime);
 166                         sleepTime <<= 1;
 167                         sleeps++;
 168                     }
 169                 } catch (InterruptedException e) {
 170                     interrupted = true;
 171                 }
 172             }
 173 
 174             // no luck
 175             throw new OutOfMemoryError
 176                 ("Cannot reserve "
 177                  + size + " bytes of direct buffer memory (allocated: "
 178                  + RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")");
 179 
 180         } finally {
 181             if (interrupted) {
 182                 // don't swallow interrupts
 183                 Thread.currentThread().interrupt();
 184             }
 185         }
 186     }
 187 
 188     private static boolean tryReserveMemory(long size, int cap) {
 189 
 190         // -XX:MaxDirectMemorySize limits the total capacity rather than the
 191         // actual memory usage, which will differ when buffers are page
 192         // aligned.
 193         long totalCap;
 194         while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
 195             if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
 196                 RESERVED_MEMORY.addAndGet(size);
 197                 COUNT.incrementAndGet();
 198                 return true;
 199             }
 200         }
 201 
 202         return false;
 203     }
 204 
 205 
 206     static void unreserveMemory(long size, int cap) {
 207         long cnt = COUNT.decrementAndGet();
 208         long reservedMem = RESERVED_MEMORY.addAndGet(-size);
 209         long totalCap = TOTAL_CAPACITY.addAndGet(-cap);
 210         assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
 211     }
 212 
 213     static final BufferPool BUFFER_POOL = new BufferPool() {
 214         @Override
 215         public String getName() {
 216             return "direct";
 217         }
 218         @Override
 219         public long getCount() {
 220             return Bits.COUNT.get();
 221         }
 222         @Override
 223         public long getTotalCapacity() {
 224             return Bits.TOTAL_CAPACITY.get();
 225         }
 226         @Override
 227         public long getMemoryUsed() {
 228             return Bits.RESERVED_MEMORY.get();
 229         }
 230     };
 231 
 232     // These numbers represent the point at which we have empirically
 233     // determined that the average cost of a JNI call exceeds the expense
 234     // of an element by element copy.  These numbers may change over time.
 235     static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;
 236     static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;
 237 }