Determine the default number of heap/direct arenas of PooledByteBufAllocator conservatively
- Fixes #1445 - Add PlatformDependent.maxDirectMemory() - Ensure the default number or arenas is decreased if the max memory of the VM is not large enough.
This commit is contained in:
parent
fe40d4b67f
commit
0da48e7e7f
@ -29,10 +29,9 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
|
||||
|
||||
private static final int DEFAULT_NUM_HEAP_ARENA = Math.max(0, SystemPropertyUtil.getInt(
|
||||
"io.netty.allocator.numHeapArenas", Runtime.getRuntime().availableProcessors()));
|
||||
private static final int DEFAULT_NUM_DIRECT_ARENA = Math.max(0, SystemPropertyUtil.getInt(
|
||||
"io.netty.allocator.numDirectArenas", Runtime.getRuntime().availableProcessors()));
|
||||
private static final int DEFAULT_NUM_HEAP_ARENA;
|
||||
private static final int DEFAULT_NUM_DIRECT_ARENA;
|
||||
|
||||
private static final int DEFAULT_PAGE_SIZE;
|
||||
private static final int DEFAULT_MAX_ORDER; // 8192 << 11 = 16 MiB per chunk
|
||||
|
||||
@ -60,6 +59,23 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
||||
}
|
||||
DEFAULT_MAX_ORDER = defaultMaxOrder;
|
||||
|
||||
// Determine reasonable default for nHeapArena and nDirectArena.
|
||||
// Assuming each arena has 3 chunks, the pool should not consume more than 50% of max memory.
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER;
|
||||
DEFAULT_NUM_HEAP_ARENA = Math.max(0,
|
||||
SystemPropertyUtil.getInt(
|
||||
"io.netty.allocator.numHeapArenas",
|
||||
(int) Math.min(
|
||||
runtime.availableProcessors(),
|
||||
Runtime.getRuntime().maxMemory() / defaultChunkSize / 2 / 3)));
|
||||
DEFAULT_NUM_DIRECT_ARENA = Math.max(0,
|
||||
SystemPropertyUtil.getInt(
|
||||
"io.netty.allocator.numDirectArenas",
|
||||
(int) Math.min(
|
||||
runtime.availableProcessors(),
|
||||
PlatformDependent.maxDirectMemory() / defaultChunkSize / 2 / 3)));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("io.netty.allocator.numHeapArenas: {}", DEFAULT_NUM_HEAP_ARENA);
|
||||
logger.debug("io.netty.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);
|
||||
|
@ -23,15 +23,20 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
@ -47,6 +52,9 @@ public final class PlatformDependent {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
|
||||
|
||||
private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile(
|
||||
"\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
|
||||
|
||||
private static final boolean IS_ANDROID = isAndroid0();
|
||||
private static final boolean IS_WINDOWS = isWindows0();
|
||||
private static final boolean IS_ROOT = isRoot0();
|
||||
@ -59,6 +67,7 @@ public final class PlatformDependent {
|
||||
private static final boolean CAN_USE_CHM_V8 = HAS_UNSAFE && JAVA_VERSION < 8;
|
||||
private static final boolean DIRECT_BUFFER_PREFERRED =
|
||||
HAS_UNSAFE && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
|
||||
private static final long MAX_DIRECT_MEMORY = maxDirectMemory0();
|
||||
|
||||
private static final long ARRAY_BASE_OFFSET = arrayBaseOffset0();
|
||||
|
||||
@ -129,6 +138,13 @@ public final class PlatformDependent {
|
||||
return DIRECT_BUFFER_PREFERRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum memory reserved for direct buffer allocation.
|
||||
*/
|
||||
public static long maxDirectMemory() {
|
||||
return MAX_DIRECT_MEMORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if Javassist is available.
|
||||
*/
|
||||
@ -469,6 +485,53 @@ public final class PlatformDependent {
|
||||
return PlatformDependent0.arrayBaseOffset();
|
||||
}
|
||||
|
||||
private static long maxDirectMemory0() {
|
||||
long maxDirectMemory = 0;
|
||||
try {
|
||||
// Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate.
|
||||
Class<?> vmClass = Class.forName("sun.misc.VM", true, ClassLoader.getSystemClassLoader());
|
||||
Method m = vmClass.getDeclaredMethod("maxDirectMemory");
|
||||
maxDirectMemory = ((Number) m.invoke(null)).longValue();
|
||||
} catch (Throwable t) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
if (maxDirectMemory <= 0) {
|
||||
// Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
|
||||
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
|
||||
List<String> vmArgs = runtime.getInputArguments();
|
||||
for (int i = vmArgs.size() - 1; i >= 0; i --) {
|
||||
Matcher m = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN.matcher(vmArgs.get(i));
|
||||
if (!m.matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
maxDirectMemory = Long.parseLong(m.group(1));
|
||||
switch (m.group(2).charAt(0)) {
|
||||
case 'k': case 'K':
|
||||
maxDirectMemory *= 1024;
|
||||
break;
|
||||
case 'm': case 'M':
|
||||
maxDirectMemory *= 1024 * 1024;
|
||||
break;
|
||||
case 'g': case 'G':
|
||||
maxDirectMemory *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDirectMemory <= 0) {
|
||||
maxDirectMemory = Runtime.getRuntime().maxMemory();
|
||||
logger.debug("maxDirectMemory: {} bytes (maybe)", maxDirectMemory);
|
||||
} else {
|
||||
logger.debug("maxDirectMemory: {} bytes", maxDirectMemory);
|
||||
}
|
||||
|
||||
return maxDirectMemory;
|
||||
}
|
||||
|
||||
private static boolean hasJavassist0() {
|
||||
boolean noJavassist = SystemPropertyUtil.getBoolean("io.netty.noJavassist", false);
|
||||
if (noJavassist) {
|
||||
|
Loading…
Reference in New Issue
Block a user