首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么XX:MaxDirectMemorySize不能限制Unsafe.allocateMemory?

为什么XX:MaxDirectMemorySize不能限制Unsafe.allocateMemory?
EN

Stack Overflow用户
提问于 2015-04-17 14:28:23
回答 2查看 3.1K关注 0票数 11

下面的代码将分配大量的直接内存,但不会导致java.lang.OutOfMemoryError:直接缓冲区内存:

代码语言:javascript
复制
//JVM args: -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m
    public class DirectMemoryOOM {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            Field f = Unsafe.class.getDeclaredFields()[0];
            f.setAccessible(true);
            Unsafe us = (Unsafe) f.get(null);
            long size = 1024 * 1024 * 1024;
            while (true) {
                long p = us.allocateMemory(size);
                for (int i = 0; i < size; i++) {
                    us.putByte(p + i, Byte.MAX_VALUE);
                }
            }
        }
    }

但是下面的代码将得到java.lang.OutOfMemoryError:直接缓冲区内存。我从Java unsafe memory allocation limit中看到了答案,但是ByteBuffer.allocateDirect是使用Unsafe.allocateMemory()实现的

代码语言:javascript
复制
//JVM args: -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m
public class DirectMemoryOOM {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        int size = 1024 * 1024;
        System.out.println(sun.misc.VM.maxDirectMemory());
        while (true) {
            ByteBuffer.allocateDirect(size);
        }
    }
}

为什么第一个限制会失败呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-17 14:41:13

正如最初的答案所述:Unsafe.allocateMemory()os::malloc的包装器,它不关心VM施加的任何内存限制。

ByteBuffer.allocateDirect()将调用此方法,但在此之前,它将调用Bits.reserveMemory() (在我的Java7:DirectByteBuffer.java:123版本中),它检查进程的内存使用情况,并抛出您提到的异常。

票数 11
EN

Stack Overflow用户

发布于 2015-04-17 14:47:06

错误来自Bits.reserveMemory,在调用allocateDirect时,它在unsafe.allocateMemory(size)之前被调用。

reserveMemory方法处理此验证:

代码语言:javascript
复制
synchronized (Bits.class) {
    if (totalCapacity + cap > maxMemory)
        throw new OutOfMemoryError("Direct buffer memory");
    reservedMemory += size;
    totalCapacity += cap;
    count++;
}

如果所需的分配高于从

代码语言:javascript
复制
maxMemory = VM.maxDirectMemory();

直接调用allocateMemory将继续本机方法,并且不会验证最大容量(这解释了为什么在第一个代码段中没有得到错误),这是--XX:MaxDirectMemorySize的主要目标,如reserveMemory中的注释所解释的那样

代码语言:javascript
复制
// -XX:MaxDirectMemorySize limits the total capacity rather than the
// actual memory usage, which will differ when buffers are page
// aligned.
if (cap <= maxMemory - totalCapacity) {
     reservedMemory += size;
     totalCapacity += cap;
     count++;
     return;
}

值得一提的是,您的第一个片段实现不是一个好的实践。Bits.java中的注释指定在分配直接内存时始终调用reserveMemory

代码语言:javascript
复制
// These methods should be called whenever direct memory is allocated or
// freed.  They allow the user to control the amount of direct memory
// which a process may access.  All sizes are specified in bytes.
static void reserveMemory(long size, int cap) {
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29702028

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档