Skip to content

Commit

Permalink
Speedup max direct memory estimation via Unsafe
Browse files Browse the repository at this point in the history
Motivation:

PlatformDependent::estimateMaxDirectMemory reflectevly allocates MX Beans to
detect JVM's arg MaxDirectMemory (often failing to find any, because unconfigured).

Modifications:

Allow unsafe to find Bits's max memory static field and use it as a fast path to detect
the same direct memory limits used by the JVM runtime

Result:

Faster and less memory hungry (in term of mallocs) startup
  • Loading branch information
franz1981 committed Sep 28, 2023
1 parent 1c7f0fa commit 13d827b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,10 @@ private static boolean isIkvmDotNet0() {
* @return The estimated max direct memory, in bytes.
*/
public static long estimateMaxDirectMemory() {
long maxDirectMemory = 0;
long maxDirectMemory = PlatformDependent0.bitsMaxDirectMemory();
if (maxDirectMemory > 0) {
return maxDirectMemory;
}

ClassLoader systemClassLoader = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.atomic.AtomicLong;

import static io.netty.util.internal.ObjectUtil.checkNotNull;

Expand Down Expand Up @@ -76,6 +77,8 @@ final class PlatformDependent0 {

private static final boolean UNALIGNED;

private static final long BITS_MAX_DIRECT_MEMORY;

static {
final ByteBuffer direct;
Field addressField = null;
Expand Down Expand Up @@ -271,6 +274,7 @@ public Object run() {
INT_ARRAY_BASE_OFFSET = -1;
INT_ARRAY_INDEX_SCALE = -1;
UNALIGNED = false;
BITS_MAX_DIRECT_MEMORY = -1;
DIRECT_BUFFER_CONSTRUCTOR = null;
ALLOCATE_ARRAY_METHOD = null;
STORE_FENCE_AVAILABLE = false;
Expand Down Expand Up @@ -336,6 +340,8 @@ public Object run() {
LONG_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(long[].class);
LONG_ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale(long[].class);
final boolean unaligned;
// using a known type to avoid loading new classes
final AtomicLong maybeMaxMemory = new AtomicLong(-1);
Object maybeUnaligned = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
Expand All @@ -345,9 +351,20 @@ public Object run() {
int version = javaVersion();
if (unsafeStaticFieldOffsetSupported() && version >= 9) {
// Java9/10 use all lowercase and later versions all uppercase.
String fieldName = version >= 11 ? "UNALIGNED" : "unaligned";
String fieldName = version >= 11? "MAX_MEMORY" : "maxMemory";
// On Java9 and later we try to directly access the field as we can do this without
// adjust the accessible levels.
try {
Field maxMemoryField = bitsClass.getDeclaredField(fieldName);
if (maxMemoryField.getType() == long.class) {
long offset = UNSAFE.staticFieldOffset(maxMemoryField);
Object object = UNSAFE.staticFieldBase(maxMemoryField);
maybeMaxMemory.lazySet(UNSAFE.getLong(object, offset));
}
} catch (Throwable ignore) {
// ignore if can't access
}
fieldName = version >= 11? "UNALIGNED" : "unaligned";
try {
Field unalignedField = bitsClass.getDeclaredField(fieldName);
if (unalignedField.getType() == boolean.class) {
Expand Down Expand Up @@ -397,6 +414,7 @@ public Object run() {
}

UNALIGNED = unaligned;
BITS_MAX_DIRECT_MEMORY = maybeMaxMemory.get() >= 0? maybeMaxMemory.get() : -1;

if (javaVersion() >= 9) {
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
Expand Down Expand Up @@ -522,6 +540,13 @@ static boolean isUnaligned() {
return UNALIGNED;
}

/**
* Any value >= 0 should be considered as a valid max direct memory value.
*/
static long bitsMaxDirectMemory() {
return BITS_MAX_DIRECT_MEMORY;
}

static boolean hasUnsafe() {
return UNSAFE != null;
}
Expand Down

0 comments on commit 13d827b

Please sign in to comment.