Java `ByteBuffer.allocateDirect`和Xmx
根据(尽管JavaDoc中没有特别提到),Java `ByteBuffer.allocateDirect`和Xmx,java,memory-management,Java,Memory Management,根据(尽管JavaDoc中没有特别提到),ByteBuffer.allocateDirect从主JVM堆中分配内存。我可以确认,使用Java任务控制,调用ByteBuffer n=ByteBuffer.allocateDirect(Integer.MAX_VALUE)的程序不会占用太多Java堆内存: 但是,当限制JVM堆内存时,这种堆外内存分配将停止工作。例如,当我使用-Xmx1g选项运行JVM时,allocateDirect调用会导致以下异常:线程“main”java.lang.OutOf
ByteBuffer.allocateDirect
从主JVM堆中分配内存。我可以确认,使用Java任务控制,调用ByteBuffer n=ByteBuffer.allocateDirect(Integer.MAX_VALUE)
的程序不会占用太多Java堆内存:
但是,当限制JVM堆内存时,这种堆外内存分配将停止工作。例如,当我使用-Xmx1g
选项运行JVM时,allocateDirect
调用会导致以下异常:线程“main”java.lang.OutOfMemoryError中的异常:直接缓冲内存
。我不完全理解这个JVM选项如何与堆外直接内存分配相关,因为根据-Xmx
选项设置Java堆空间大小。如果我使用getUnsafe().allocateMemory(Integer.MAX_值)分配内存代码>内存已成功分配。我的JVM如下所示:
java版本“10”2018-03-20 java(TM)SE运行时环境18.3
(构建10+46)Java热点(TM)64位服务器VM 18.3(构建10+46,
混合模式)
在Xmx
和ByteBuffer.allocateDirect
之间是否会出现这种行为
编辑:JDK1.7中似乎存在一个与上述行为相同的(不可复制的)。这是一个bug吗?好吧,这不是bug,让我告诉你为什么allocateDirect
会导致OOM
。
在JVM中,您已经知道设置最大JVM堆大小的-Xmx
选项。但是你必须知道JVM内存(堆)也是你电脑内存的一部分。
简单来说,这意味着您的PC内存
=JVM
+直接内存
。
因此,当您将JVM选项设置为“-Xmx1g”并获得OOM
异常时,请检查并确保您有足够的内存(电脑的其余内存)来运行allocateDirect
希望它能帮助你 我不得不去寻觅拾荒者来寻找原因,但你来了
首先,我查看了ByteBuffer#allocateDirect
,发现如下内容:
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
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;
}
然后我导航到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");
我对maxMemory
字段很好奇,并查看它的声明位置:
private static volatile long maxMemory = VM.maxDirectMemory();
现在我必须查看VM.java
中的maxDirectMemory
:
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;
这太棒了,谢谢
/**
* 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();