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 }