< prev index next >
src/java.base/share/classes/java/nio/Bits.java
Print this page
*** 24,39 ****
*/
package java.nio;
import java.util.concurrent.atomic.AtomicLong;
! import jdk.internal.misc.JavaNioAccess;
! import jdk.internal.misc.JavaLangRefAccess;
! import jdk.internal.misc.SharedSecrets;
! import jdk.internal.misc.Unsafe;
! import jdk.internal.misc.VM;
/**
* Access to bits, native and otherwise.
*/
--- 24,37 ----
*/
package java.nio;
import java.util.concurrent.atomic.AtomicLong;
+ import java.util.concurrent.locks.ReentrantLock;
! import jdk.internal.misc.*;
! import jdk.internal.ref.CleanerFactory;
/**
* Access to bits, native and otherwise.
*/
*** 607,616 ****
--- 605,616 ----
// 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;
+ private static final ReentrantLock reservationQueue = new ReentrantLock(true);
+
// 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.
static void reserveMemory(long size, int cap) {
*** 622,677 ****
// optimist!
if (tryReserveMemory(size, cap)) {
return;
}
! final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
! // retry while helping enqueue pending Reference objects
! // which includes executing pending Cleaner(s) which includes
! // Cleaner(s) that free direct buffer memory
! while (jlra.tryHandlePendingReference()) {
if (tryReserveMemory(size, cap)) {
return;
}
! }
! // trigger VM's Reference processing
System.gc();
! // a retry loop with exponential back-off delays
! // (this gives VM some time to do it's job)
! boolean interrupted = false;
! try {
! long sleepTime = 1;
! int sleeps = 0;
! while (true) {
if (tryReserveMemory(size, cap)) {
return;
}
! if (sleeps >= MAX_SLEEPS) {
! break;
! }
! if (!jlra.tryHandlePendingReference()) {
! try {
! Thread.sleep(sleepTime);
! sleepTime <<= 1;
! sleeps++;
! } catch (InterruptedException e) {
! interrupted = true;
! }
! }
! }
// no luck
throw new OutOfMemoryError("Direct buffer memory");
-
} finally {
! if (interrupted) {
! // don't swallow interrupts
! Thread.currentThread().interrupt();
! }
}
}
private static boolean tryReserveMemory(long size, int cap) {
--- 622,664 ----
// optimist!
if (tryReserveMemory(size, cap)) {
return;
}
! // reservation threads that don't succeed at first must queue so that
! // some of them don't starve while others succeed.
! reservationQueue.lock();
! try {
! JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
! // retry reservation while helping the Cleaner thread process enqueued
! // Cleanable(s) which includes the ones that free direct buffer memory
! // until the queue drains out
! do {
if (tryReserveMemory(size, cap)) {
return;
}
! } while (jlra.cleanNextPendingCleanable(CleanerFactory.cleaner()));
! // trigger GC's Reference discovery
System.gc();
+ // make sure all newly discovered Reference(s) are enqueued
+ jlra.enqueuePendingReferences();
! // retry reservation while helping the Cleaner thread process enqueued
! // Cleanable(s) which includes the ones that free direct buffer memory
! // until the queue drains out
! do {
if (tryReserveMemory(size, cap)) {
return;
}
! } while (jlra.cleanNextPendingCleanable(CleanerFactory.cleaner()));
// no luck
throw new OutOfMemoryError("Direct buffer memory");
} finally {
! reservationQueue.unlock();
}
}
private static boolean tryReserveMemory(long size, int cap) {
< prev index next >