gpt4 book ai didi

java - `ByteBuffer.allocateDirect` 和 Xmx

转载 作者:搜寻专家 更新时间:2023-11-01 01:40:05 25 4
gpt4 key购买 nike

根据 various sources (尽管在 JavaDoc 中没有特别提到),ByteBuffer.allocateDirect 分配主 JVM 堆之外的内存。我可以确认使用 Java Mission Control,看到调用 ByteBuffer n = ByteBuffer.allocateDirect(Integer.MAX_VALUE) 的程序没有使用太多 Java 堆内存:

enter image description here

但是,当限制 JVM 堆内存时,此堆外内存分配将停止工作。例如,当我使用 -Xmx1g 选项运行 JVM 时,allocateDirect 调用导致以下异常:Exception in thread "main"java.lang.OutOfMemoryError:直接缓冲内存。我不完全理解这个 JVM 选项如何与堆外直接内存分配相关,因为 - 根据 documentation - -Xmx 选项设置 Java 堆空间大小。如果我使用 getUnsafe().allocateMemory(Integer.MAX_VALUE); 分配内存,则内存分配成功。我的 JVM 如下:

java version "10" 2018-03-20 Java(TM) SE Runtime Environment 18.3 (build 10+46) Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)

XmxByteBuffer.allocateDirect 之间的这种行为是否符合预期?

编辑:似乎有一个(不可复制的)bug在 JDK 1.7 中具有与上述相同的行为。那么这是一个错误吗?

最佳答案

我不得不继续寻找寻宝游戏来寻找原因,但是给你!

首先,我查看了ByteBuffer#allocateDirect并发现以下内容:

public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}

然后我导航到 DirectByteBuffer 的构造函数并找到以下方法调用:

Bits.reserveMemory(size, cap);

查看这个方法,我们看到:

while (true) {
if (tryReserveMemory(size, cap)) {
return;
}

if (sleeps >= MAX_SLEEPS) {
break;
}

try {
if (!jlra.waitForReferenceProcessing()) {
Thread.sleep(sleepTime);
sleepTime <<= 1;
sleeps++;
}
} catch (InterruptedException e) {
interrupted = true;
}
}

// no luck
throw new OutOfMemoryError("Direct buffer memory");

这似乎是您收到此错误的地方,但现在我们需要找出造成错误的原因。为此,我调查了对 tryReserveMemory 的调用。并发现以下内容:

private static boolean tryReserveMemory(long size, int cap) {
long totalCap;

while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
reservedMemory.addAndGet(size);
count.incrementAndGet();
return true;
}
}

return false;
}

我很好奇 maxMemory字段,并查看声明它的位置:

private static volatile long maxMemory = VM.maxDirectMemory();

现在我必须查看 maxDirectMemoryVM.java 内:

public static long maxDirectMemory() {
return directMemory;
}

最后我们来看directMemory的声明:

// A user-settable upper limit on the maximum amount of allocatable direct
// buffer memory. This value may be changed during VM initialization if
// "java" is launched with "-XX:MaxDirectMemorySize=<size>".
//
// The initial value of this field is arbitrary; during JRE initialization
// it will be reset to the value specified on the command line, if any,
// otherwise to Runtime.getRuntime().maxMemory().
//
private static long directMemory = 64 * 1024 * 1024;

嘿,看那个!如果您不使用 "-XX:MaxDirectMemorySize=<size>" 手动指定它, 那么它默认为 Runtime.getRuntime().maxMemory() ,这是您设置的堆大小。

视为 -Xmx1G小于 Integer.MAX_VALUE字节,调用 tryReserveMemory永远返回true ,结果为 sleeps >= MAX_SLEEPS , 跳出 while 循环,抛出你的 OutOfMemoryError .

如果我们看Runtime.getRuntime().maxMemory() ,然后我们就会明白为什么如果您指定最大堆大小它会起作用:

/**
* Returns the maximum amount of memory that the Java virtual machine
* will attempt to use. If there is no inherent limit then the value
* {@link java.lang.Long#MAX_VALUE} will be returned.
*
* @return the maximum amount of memory that the virtual machine will
* attempt to use, measured in bytes
* @since 1.4
*/
public native long maxMemory();

关于java - `ByteBuffer.allocateDirect` 和 Xmx,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50499238/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com