- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
根据 various sources (尽管在 JavaDoc 中没有特别提到),ByteBuffer.allocateDirect
分配主 JVM 堆之外的内存。我可以确认使用 Java Mission Control,看到调用 ByteBuffer n = ByteBuffer.allocateDirect(Integer.MAX_VALUE)
的程序没有使用太多 Java 堆内存:
但是,当限制 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)
Xmx
和 ByteBuffer.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();
现在我必须查看 maxDirectMemory
在 VM.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/
我想知道当没有可用内存时,allocateDirect 和 allocate from ByteBuffer 会返回空指针还是其他什么? (我在java文档中找不到它)。提前致谢。 最佳答案 对于这两
我使用浮点缓冲区作为 Android 中 opengl 绘图所需的直接字节缓冲区。问题是,在创建字节缓冲区时,GC 会变得疯狂——就像 30 多秒一样疯狂。我正在创建一个 40x40 顶点、1600
我今天读了以下内容: Direct ByteBuffer objects clean up their native buffers automatically but can only do so
根据 various sources (尽管在 JavaDoc 中没有特别提到),ByteBuffer.allocateDirect 分配主 JVM 堆之外的内存。我可以确认使用 Java Missi
本文整理了Java中com.yahoo.memory.WritableMemory.allocateDirect()方法的一些代码示例,展示了WritableMemory.allocateDirect
我正在研究一些SocketChannel到SocketChannel的代码,这些代码最适合直接字节缓冲区-长寿且很大(每个连接数十到数百兆字节)。在用FileChannel散列确切的循环结构时,我运行
我刚刚解决了一个错误,但我不知道为什么。在 LWJGL 中创建 4x4 投影矩阵,用于顶点着色器.. 该行会导致问题。它会默默地失败,并且着色器中的 mat4 被卡为全零(就好像它从未被写入一样)。
分配零长度缓冲区通常取决于实现。 我知道 malloc(0) 返回 NULL 或可以安全释放的指针,这完全取决于实现。 那么,当调用 ByteBuffer.allocateDirect(0) 时会发生
我正在尝试制作堆外内存缓冲区。我想要非常大的缓冲区(比如 10GB)。我听说 jvm 堆有时会因为 full GC 而卡住。因此,我尝试使用 java.nio.ByteBuffer 制作缓冲区。 但是
我试图通过使用 MappedByteBuffer 对特定文件进行内存映射,在两个或多个 JVM 之间实现一种共享缓存。从规范中我看到,当我们使用 MappedByteBuffer.load() 时,它
我在以下代码中得到了 UnsupportedOperationException: byte[] temp = ByteBuffer.allocateDirect(10).array(); 我检查了j
为什么 CharBuffer 中有 isDirect() 方法? 如果 CharBuffer 或 Buffer 中没有任何相应的 (allocateDirect) 方法,我们如何分配直接 CharBu
我是安卓新手。我似乎找不到相关的论坛帖子。 令我困惑的是 allocateDirect() 确实在 Android 4.2 模拟器中创建支持 byte[]。 更具体地说,我分配一个 ByteBuffe
我有一个每 600 毫秒运行一次的游戏服务器,在一个周期内操作一个字节数组,然后在周期结束时将字节数组写入客户端。 由于在循环结束时需要写入多少字节的不确定性,我在循环结束时为每次写入创建了一个字节缓
从示例中复制并粘贴源代码是一回事,但我正在寻找一些答案来解释为什么示例是这样的。 我无法回答的一个问题是为什么三角形的 ByteBuffer 每个坐标需要四个字节。 在 example present
我是一名优秀的程序员,十分优秀!