Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Speedup max direct memory estimation via Unsafe
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
commit 13d827b56ab2c3b89673a22885d54f3482bb8fc7
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