使用-Xmx1G
标志提供一千兆字节的堆,以下工作方式如下:
public class Biggy {
public static void main(String[] args) {
int[] array = new int[150 * 1000 * 1000];
}
}
数组应该代表大约600 MB。
但是,以下命令抛出OutOfMemoryError:
public class Biggy {
public static void main(String[] args) {
int[] array = new int[200 * 1000 * 1000];
}
}
尽管数组应该代表大约800 MB,因此很容易适合内存。
遗失的记忆在哪里?
答案 0 :(得分:19)
在Java中,堆中通常有多个区域(和子区域)。你有一个年轻而终身的地区,拥有大多数收藏家。大型阵列会立即添加到终端区域,但根据您的最大内存大小,将为年轻空间预留一些空间。如果你缓慢地分配内存,这些区域将会调整大小,但像这样的大块可能会失败,如你所见。
鉴于内存通常相对便宜(并非总是如此),我只会将最大值增加到您希望应用程序失败的程度,如果它曾经使用过那么多。
BTW:如果您有这样的大型结构,可以考虑使用直接内存。
IntBuffer array = ByteBuffer.allocateDirect(200*1000*1000*4)
.order(ByteOrder.nativeOrder()).asIntBuffer();
int a = array.get(n);
array.put(n, a+1);
编写它有点乏味,但有一个很大的优点,它几乎不使用堆。 (头顶不到1 KB)
答案 1 :(得分:3)
有足够的可用内存但不是一个连续的 内存块,根据数组的需要。
您可以使用使用较小块的其他数据结构吗? 内存,或几个较小的数组?
例如,以下代码适用于-Xmx1G
:
public class Biggy {
public static void main(String[] args) {
int [][]array = new int[200][];
for (int i = 0; i < 200; i++) {
array[i] = new int[1000 * 1000];
System.out.println("i=" + i);
}
}
}
答案 2 :(得分:1)
堆内存分为三个空格:
一开始,这个对象将存在于旧一代中,并将在这里停留一段时间。
默认情况下,虚拟机会在每个集合中增大或缩小堆,以尝试将可用空间的比例保持为特定范围内每个集合的活动对象。此目标范围通过参数-XX:MinHeapFreeRatio =和-XX:MaxHeapFreeRatio =设置为百分比,并且总大小在-Xms以下由-Xms以上限制。
我的jvm中的默认比率是30/70,因此旧代的对象的最大大小是有限的(使用-Xmx1G)700Mb(顺便说一句,我在使用默认的jvm参数运行时得到相同的异常)。
但是你可以使用jvm选项调整代数。比如你可以
使用参数-Xmx1G -XX:NewRatio=10
和new int[200 * 1000 * 1000];
运行您的课程将会成功。
据我所知,Java并不是为了在内存中保存大型对象而设计的。应用程序中内存的典型用法是一堆相对较小的对象的图形,通常只有在所有空格中空间不足时才会出现OutOfMemoryError。
下面是一些有用的(和有趣的阅读)文章:
Ergonomics in the 5.0 Java[tm] Virtual Machine
Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine