2007-12-01 00:00:00 +00:00
|
|
|
/*
|
2016-02-10 15:20:41 -08:00
|
|
|
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
2007-12-01 00:00:00 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
2010-05-25 15:58:33 -07:00
|
|
|
* published by the Free Software Foundation. Oracle designates this
|
2007-12-01 00:00:00 +00:00
|
|
|
* particular file as subject to the "Classpath" exception as provided
|
2010-05-25 15:58:33 -07:00
|
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
2007-12-01 00:00:00 +00:00
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
2010-05-25 15:58:33 -07:00
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
2007-12-01 00:00:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
package java.nio;
|
|
|
|
|
2015-09-28 13:39:27 +01:00
|
|
|
import jdk.internal.misc.JavaLangRefAccess;
|
2016-07-15 12:36:15 +02:00
|
|
|
import jdk.internal.misc.JavaNioAccess;
|
2015-09-28 13:39:27 +01:00
|
|
|
import jdk.internal.misc.SharedSecrets;
|
2015-10-27 14:19:55 +00:00
|
|
|
import jdk.internal.misc.Unsafe;
|
2016-01-06 10:01:44 +00:00
|
|
|
import jdk.internal.misc.VM;
|
2007-12-01 00:00:00 +00:00
|
|
|
|
2016-07-15 12:36:15 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
|
2007-12-01 00:00:00 +00:00
|
|
|
/**
|
|
|
|
* Access to bits, native and otherwise.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Bits { // package-private
|
|
|
|
|
|
|
|
private Bits() { }
|
|
|
|
|
|
|
|
|
|
|
|
// -- Swapping --
|
|
|
|
|
|
|
|
static short swap(short x) {
|
2010-06-30 16:11:32 -07:00
|
|
|
return Short.reverseBytes(x);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char swap(char x) {
|
2010-06-30 16:11:32 -07:00
|
|
|
return Character.reverseBytes(x);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int swap(int x) {
|
2010-06-30 16:11:32 -07:00
|
|
|
return Integer.reverseBytes(x);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static long swap(long x) {
|
2010-06-30 16:11:32 -07:00
|
|
|
return Long.reverseBytes(x);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Unsafe access --
|
|
|
|
|
|
|
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
|
|
|
|
|
|
|
static Unsafe unsafe() {
|
|
|
|
return unsafe;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Processor and memory-system properties --
|
|
|
|
|
2015-03-31 12:30:52 -07:00
|
|
|
private static final ByteOrder byteOrder
|
|
|
|
= unsafe.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
static ByteOrder byteOrder() {
|
|
|
|
return byteOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int pageSize = -1;
|
|
|
|
|
|
|
|
static int pageSize() {
|
|
|
|
if (pageSize == -1)
|
|
|
|
pageSize = unsafe().pageSize();
|
|
|
|
return pageSize;
|
|
|
|
}
|
|
|
|
|
2010-07-29 13:08:58 +01:00
|
|
|
static int pageCount(long size) {
|
|
|
|
return (int)(size + (long)pageSize() - 1L) / pageSize();
|
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
|
2015-03-31 12:30:52 -07:00
|
|
|
private static boolean unaligned = unsafe.unalignedAccess();
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
static boolean unaligned() {
|
|
|
|
return unaligned;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Direct memory management --
|
|
|
|
|
|
|
|
// A user-settable upper limit on the maximum amount of allocatable
|
|
|
|
// direct buffer memory. This value may be changed during VM
|
|
|
|
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
|
|
|
|
private static volatile long maxMemory = VM.maxDirectMemory();
|
2014-02-24 15:34:33 +01:00
|
|
|
private static final AtomicLong reservedMemory = new AtomicLong();
|
|
|
|
private static final AtomicLong totalCapacity = new AtomicLong();
|
|
|
|
private static final AtomicLong count = new AtomicLong();
|
2015-12-21 20:54:00 +01:00
|
|
|
private static volatile boolean memoryLimitSet;
|
|
|
|
|
2014-02-24 15:34:33 +01:00
|
|
|
// max. number of sleeps during try-reserving with exponentially
|
|
|
|
// increasing delay before throwing OutOfMemoryError:
|
|
|
|
// 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
|
|
|
|
// which means that OOME will be thrown after 0.5 s of trying
|
|
|
|
private static final int MAX_SLEEPS = 9;
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// These methods should be called whenever direct memory is allocated or
|
|
|
|
// freed. They allow the user to control the amount of direct memory
|
|
|
|
// which a process may access. All sizes are specified in bytes.
|
2008-08-26 10:21:22 +01:00
|
|
|
static void reserveMemory(long size, int cap) {
|
2014-02-24 15:34:33 +01:00
|
|
|
|
8142968: Module System implementation
Initial integration of JEP 200, JEP 260, JEP 261, and JEP 282
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com>
Co-authored-by: Mandy Chung <mandy.chung@oracle.com>
Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Alexandr Scherbatiy <alexandr.scherbatiy@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Co-authored-by: Calvin Cheung <calvin.cheung@oracle.com>
Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com>
Co-authored-by: Erik Joelsson <erik.joelsson@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Jaroslav Bachorik <jaroslav.bachorik@oracle.com>
Co-authored-by: Jean-Francois Denise <jean-francois.denise@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: James Laskey <james.laskey@oracle.com>
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: Miroslav Kos <miroslav.kos@oracle.com>
Co-authored-by: Huaming Li <huaming.li@oracle.com>
Co-authored-by: Sean Mullan <sean.mullan@oracle.com>
Co-authored-by: Naoto Sato <naoto.sato@oracle.com>
Co-authored-by: Masayoshi Okutsu <masayoshi.okutsu@oracle.com>
Co-authored-by: Peter Levart <peter.levart@gmail.com>
Co-authored-by: Philip Race <philip.race@oracle.com>
Co-authored-by: Claes Redestad <claes.redestad@oracle.com>
Co-authored-by: Sergey Bylokhov <sergey.bylokhov@oracle.com>
Co-authored-by: Alexandre Iline <alexandre.iline@oracle.com>
Co-authored-by: Volker Simonis <volker.simonis@gmail.com>
Co-authored-by: Staffan Larsen <staffan.larsen@oracle.com>
Co-authored-by: Stuart Marks <stuart.marks@oracle.com>
Co-authored-by: Semyon Sadetsky <semyon.sadetsky@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Sundararajan Athijegannathan <sundararajan.athijegannathan@oracle.com>
Co-authored-by: Valerie Peng <valerie.peng@oracle.com>
Co-authored-by: Vincent Ryan <vincent.x.ryan@oracle.com>
Co-authored-by: Weijun Wang <weijun.wang@oracle.com>
Co-authored-by: Yuri Nesterenko <yuri.nesterenko@oracle.com>
Co-authored-by: Yekaterina Kantserova <yekaterina.kantserova@oracle.com>
Co-authored-by: Alexander Kulyakthin <alexander.kulyakhtin@oracle.com>
Co-authored-by: Felix Yang <felix.yang@oracle.com>
Co-authored-by: Andrei Eremeev <andrei.eremeev@oracle.com>
Co-authored-by: Frank Yuan <frank.yuan@oracle.com>
Co-authored-by: Sergei Pikalev <sergei.pikalev@oracle.com>
Co-authored-by: Sibabrata Sahoo <sibabrata.sahoo@oracle.com>
Co-authored-by: Tiantian Du <tiantian.du@oracle.com>
Co-authored-by: Sha Jiang <sha.jiang@oracle.com>
Reviewed-by: alanb, mchung, naoto, rriggs, psandoz, plevart, mullan, ascarpino, vinnie, prr, sherman, dfuchs, mhaupt
2016-03-17 19:04:16 +00:00
|
|
|
if (!memoryLimitSet && VM.initLevel() >= 1) {
|
2014-02-24 15:34:33 +01:00
|
|
|
maxMemory = VM.maxDirectMemory();
|
|
|
|
memoryLimitSet = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// optimist!
|
|
|
|
if (tryReserveMemory(size, cap)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
|
|
|
|
boolean interrupted = false;
|
2007-12-01 00:00:00 +00:00
|
|
|
try {
|
2016-08-30 23:46:02 -04:00
|
|
|
|
|
|
|
// Retry allocation until success or there are no more
|
|
|
|
// references (including Cleaners that might free direct
|
|
|
|
// buffer memory) to process and allocation still fails.
|
|
|
|
boolean refprocActive;
|
|
|
|
do {
|
|
|
|
try {
|
|
|
|
refprocActive = jlra.waitForReferenceProcessing();
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
// Defer interrupts and keep trying.
|
|
|
|
interrupted = true;
|
|
|
|
refprocActive = true;
|
|
|
|
}
|
|
|
|
if (tryReserveMemory(size, cap)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} while (refprocActive);
|
|
|
|
|
|
|
|
// trigger VM's Reference processing
|
|
|
|
System.gc();
|
|
|
|
|
|
|
|
// A retry loop with exponential back-off delays.
|
|
|
|
// Sometimes it would suffice to give up once reference
|
|
|
|
// processing is complete. But if there are many threads
|
|
|
|
// competing for memory, this gives more opportunities for
|
|
|
|
// any given thread to make progress. In particular, this
|
|
|
|
// seems to be enough for a stress test like
|
|
|
|
// DirectBufferAllocTest to (usually) succeed, while
|
|
|
|
// without it that test likely fails. Since failure here
|
|
|
|
// ends in OOME, there's no need to hurry.
|
2014-02-24 15:34:33 +01:00
|
|
|
long sleepTime = 1;
|
|
|
|
int sleeps = 0;
|
|
|
|
while (true) {
|
|
|
|
if (tryReserveMemory(size, cap)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sleeps >= MAX_SLEEPS) {
|
|
|
|
break;
|
|
|
|
}
|
2016-08-30 23:46:02 -04:00
|
|
|
try {
|
|
|
|
if (!jlra.waitForReferenceProcessing()) {
|
2014-02-24 15:34:33 +01:00
|
|
|
Thread.sleep(sleepTime);
|
|
|
|
sleepTime <<= 1;
|
|
|
|
sleeps++;
|
|
|
|
}
|
2016-08-30 23:46:02 -04:00
|
|
|
} catch (InterruptedException e) {
|
|
|
|
interrupted = true;
|
2014-02-24 15:34:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no luck
|
|
|
|
throw new OutOfMemoryError("Direct buffer memory");
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
if (interrupted) {
|
|
|
|
// don't swallow interrupts
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2014-02-24 15:34:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean tryReserveMemory(long size, int cap) {
|
|
|
|
|
|
|
|
// -XX:MaxDirectMemorySize limits the total capacity rather than the
|
|
|
|
// actual memory usage, which will differ when buffers are page
|
|
|
|
// aligned.
|
|
|
|
long totalCap;
|
|
|
|
while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
|
|
|
|
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
|
|
|
|
reservedMemory.addAndGet(size);
|
|
|
|
count.incrementAndGet();
|
|
|
|
return true;
|
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2014-02-24 15:34:33 +01:00
|
|
|
return false;
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2014-02-24 15:34:33 +01:00
|
|
|
|
|
|
|
static void unreserveMemory(long size, int cap) {
|
|
|
|
long cnt = count.decrementAndGet();
|
|
|
|
long reservedMem = reservedMemory.addAndGet(-size);
|
|
|
|
long totalCap = totalCapacity.addAndGet(-cap);
|
|
|
|
assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2009-06-27 21:49:41 +01:00
|
|
|
// -- Monitoring of direct buffer usage --
|
2008-08-26 10:21:22 +01:00
|
|
|
|
|
|
|
static {
|
|
|
|
// setup access to this package in SharedSecrets
|
2015-09-28 13:39:27 +01:00
|
|
|
SharedSecrets.setJavaNioAccess(
|
|
|
|
new JavaNioAccess() {
|
2008-08-26 10:21:22 +01:00
|
|
|
@Override
|
2015-09-28 13:39:27 +01:00
|
|
|
public JavaNioAccess.BufferPool getDirectBufferPool() {
|
|
|
|
return new JavaNioAccess.BufferPool() {
|
2009-06-27 21:49:41 +01:00
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
return "direct";
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public long getCount() {
|
2014-02-24 15:34:33 +01:00
|
|
|
return Bits.count.get();
|
2009-06-27 21:49:41 +01:00
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public long getTotalCapacity() {
|
2014-02-24 15:34:33 +01:00
|
|
|
return Bits.totalCapacity.get();
|
2009-06-27 21:49:41 +01:00
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public long getMemoryUsed() {
|
2014-02-24 15:34:33 +01:00
|
|
|
return Bits.reservedMemory.get();
|
2009-06-27 21:49:41 +01:00
|
|
|
}
|
|
|
|
};
|
2008-08-26 10:21:22 +01:00
|
|
|
}
|
2011-08-11 12:40:24 +01:00
|
|
|
@Override
|
|
|
|
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
|
|
|
|
return new DirectByteBuffer(addr, cap, ob);
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void truncate(Buffer buf) {
|
|
|
|
buf.truncate();
|
|
|
|
}
|
2009-06-27 21:49:41 +01:00
|
|
|
});
|
2008-08-26 10:21:22 +01:00
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// These numbers represent the point at which we have empirically
|
|
|
|
// determined that the average cost of a JNI call exceeds the expense
|
|
|
|
// of an element by element copy. These numbers may change over time.
|
|
|
|
static final int JNI_COPY_TO_ARRAY_THRESHOLD = 6;
|
|
|
|
static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;
|
|
|
|
}
|