Path: blob/master/src/java.base/share/classes/java/nio/Bits.java
41152 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.nio;2627import jdk.internal.access.JavaLangRefAccess;28import jdk.internal.access.SharedSecrets;29import jdk.internal.misc.Unsafe;30import jdk.internal.misc.VM;31import jdk.internal.misc.VM.BufferPool;3233import java.util.concurrent.atomic.AtomicLong;3435/**36* Access to bits, native and otherwise.37*/3839class Bits { // package-private4041private Bits() { }424344// -- Swapping --4546static short swap(short x) {47return Short.reverseBytes(x);48}4950static char swap(char x) {51return Character.reverseBytes(x);52}5354static int swap(int x) {55return Integer.reverseBytes(x);56}5758static long swap(long x) {59return Long.reverseBytes(x);60}616263// -- Unsafe access --6465private static final Unsafe UNSAFE = Unsafe.getUnsafe();6667// -- Processor and memory-system properties --6869private static int PAGE_SIZE = -1;7071static int pageSize() {72if (PAGE_SIZE == -1)73PAGE_SIZE = UNSAFE.pageSize();74return PAGE_SIZE;75}7677static long pageCount(long size) {78return (size + (long)pageSize() - 1L) / pageSize();79}8081private static boolean UNALIGNED = UNSAFE.unalignedAccess();8283static boolean unaligned() {84return UNALIGNED;85}868788// -- Direct memory management --8990// A user-settable upper limit on the maximum amount of allocatable91// direct buffer memory. This value may be changed during VM92// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".93private static volatile long MAX_MEMORY = VM.maxDirectMemory();94private static final AtomicLong RESERVED_MEMORY = new AtomicLong();95private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();96private static final AtomicLong COUNT = new AtomicLong();97private static volatile boolean MEMORY_LIMIT_SET;9899// max. number of sleeps during try-reserving with exponentially100// increasing delay before throwing OutOfMemoryError:101// 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)102// which means that OOME will be thrown after 0.5 s of trying103private static final int MAX_SLEEPS = 9;104105// These methods should be called whenever direct memory is allocated or106// freed. They allow the user to control the amount of direct memory107// which a process may access. All sizes are specified in bytes.108static void reserveMemory(long size, long cap) {109110if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {111MAX_MEMORY = VM.maxDirectMemory();112MEMORY_LIMIT_SET = true;113}114115// optimist!116if (tryReserveMemory(size, cap)) {117return;118}119120final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();121boolean interrupted = false;122try {123124// Retry allocation until success or there are no more125// references (including Cleaners that might free direct126// buffer memory) to process and allocation still fails.127boolean refprocActive;128do {129try {130refprocActive = jlra.waitForReferenceProcessing();131} catch (InterruptedException e) {132// Defer interrupts and keep trying.133interrupted = true;134refprocActive = true;135}136if (tryReserveMemory(size, cap)) {137return;138}139} while (refprocActive);140141// trigger VM's Reference processing142System.gc();143144// A retry loop with exponential back-off delays.145// Sometimes it would suffice to give up once reference146// processing is complete. But if there are many threads147// competing for memory, this gives more opportunities for148// any given thread to make progress. In particular, this149// seems to be enough for a stress test like150// DirectBufferAllocTest to (usually) succeed, while151// without it that test likely fails. Since failure here152// ends in OOME, there's no need to hurry.153long sleepTime = 1;154int sleeps = 0;155while (true) {156if (tryReserveMemory(size, cap)) {157return;158}159if (sleeps >= MAX_SLEEPS) {160break;161}162try {163if (!jlra.waitForReferenceProcessing()) {164Thread.sleep(sleepTime);165sleepTime <<= 1;166sleeps++;167}168} catch (InterruptedException e) {169interrupted = true;170}171}172173// no luck174throw new OutOfMemoryError175("Cannot reserve "176+ size + " bytes of direct buffer memory (allocated: "177+ RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")");178179} finally {180if (interrupted) {181// don't swallow interrupts182Thread.currentThread().interrupt();183}184}185}186187private static boolean tryReserveMemory(long size, long cap) {188189// -XX:MaxDirectMemorySize limits the total capacity rather than the190// actual memory usage, which will differ when buffers are page191// aligned.192long totalCap;193while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {194if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {195RESERVED_MEMORY.addAndGet(size);196COUNT.incrementAndGet();197return true;198}199}200201return false;202}203204205static void unreserveMemory(long size, long cap) {206long cnt = COUNT.decrementAndGet();207long reservedMem = RESERVED_MEMORY.addAndGet(-size);208long totalCap = TOTAL_CAPACITY.addAndGet(-cap);209assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;210}211212static final BufferPool BUFFER_POOL = new BufferPool() {213@Override214public String getName() {215return "direct";216}217@Override218public long getCount() {219return Bits.COUNT.get();220}221@Override222public long getTotalCapacity() {223return Bits.TOTAL_CAPACITY.get();224}225@Override226public long getMemoryUsed() {227return Bits.RESERVED_MEMORY.get();228}229};230231// These numbers represent the point at which we have empirically232// determined that the average cost of a JNI call exceeds the expense233// of an element by element copy. These numbers may change over time.234static final int JNI_COPY_TO_ARRAY_THRESHOLD = 6;235static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;236}237238239