尽管有足够的可用内存,但巨大的数组会丢失内存

dag*_*ies 14 java memory arrays

使用该-Xmx1G标志提供一千兆字节的堆,以下按预期工作:

public class Biggy {
    public static void main(String[] args) {
        int[] array = new int[150 * 1000 * 1000];
    }
}
Run Code Online (Sandbox Code Playgroud)

该数组应代表约600 MB.

但是,以下抛出OutOfMemoryError:

public class Biggy {
    public static void main(String[] args) {
        int[] array = new int[200 * 1000 * 1000];
    }
}
Run Code Online (Sandbox Code Playgroud)

尽管阵列应该代表大约800 MB,因此很容易适合内存.

丢失的记忆在哪里消失了?

Pet*_*rey 19

在Java中,您通常在堆中有多个区域(和子区域).你有一个年轻而终身的地区,拥有大多数收藏家.大型阵列会立即添加到终端区域,但根据您的最大内存大小,将为年轻空间预留一些空间.如果你慢慢分配内存,这些区域会调整大小,但是这样的大块可能会像你看到的那样失败.

鉴于内存通常相对便宜(并非总是如此),我只会将最大值增加到您希望应用程序失败的程度,如果它曾经使用过那么多.

顺便说一句:如果您有这样的大型结构,您可以考虑使用直接内存.

IntBuffer array = ByteBuffer.allocateDirect(200*1000*1000*4)
                            .order(ByteOrder.nativeOrder()).asIntBuffer();

int a = array.get(n);
array.put(n, a+1);
Run Code Online (Sandbox Code Playgroud)

编写它有点乏味,但有一个很大的优点,它几乎不使用堆.(头顶不到1 KB)