我想用Java中的-Xmx选项进行实验,并创建了一个简单的测试程序,该程序会一次分配1个Mib,直到内存用尽。
import java.util.Vector;
public class MemoryMuncher {
static final int MiB = 1048576;
static final int accellerator = 1;
public static void main(String[] args) {
Vector victor = new Vector();
int i = 1;
try {
while (true) {
byte roger[] = new byte[MiB * accellerator];
victor.add(roger);
Runtime rt = Runtime.getRuntime();
System.out.printf("free: %,6d\t\ttotal: %,6d\t\tallocated: %,6d \n", rt.freeMemory()/MiB, rt.totalMemory()/MiB, i++*accellerator);
}
} catch (OutOfMemoryError e) {
System.out.println(e);
}
}
}
当我使用-Xmx选项运行程序时,我注意到Java 8(1.8.0.131)和Java 9(9.0.1)之间的行为有所不同。
Java 8 的工作接近我的期望。当我使用-Xmx256M运行程序时,它会在抛出OutOfMemoryError之前分配233MiB。
free: 361 total: 368 allocated: 1
free: 360 total: 368 allocated: 2
...
free: 12 total: 245 allocated: 232
free: 11 total: 245 allocated: 233
java.lang.OutOfMemoryError: Java heap space
但是,当我使用 Java 9 运行相同的程序时,在得到异常之前,它只有大约 halfway (127 MiB)。这是一致的。如果将-Xmx更改为512M或1024M,则只能达到该数量的一半(分别为255 MiB和510 MiB)。我对此行为没有任何解释。
free: 250 total: 256 allocated: 1
free: 247 total: 256 allocated: 2
...
free: 2 total: 256 allocated: 126
free: 1 total: 256 allocated: 127
java.lang.OutOfMemoryError: Java heap space
我已经在文档中搜索了Java 8和Java 9之间的内存管理方面的任何更改,但是没有发现任何内容。
有人能理解为什么Java 9在某些情况下会与以前的Java版本以不同的方式管理/分配内存吗?
答案 0 :(得分:2)
我发现this关于Java 9如何计划以不同方式进行垃圾回收的有趣文章。
更具体地说,Java 9计划使用G1垃圾收集器,该收集器将内存划分为固定大小。您的代码可能正在执行的操作是触发将内存拆分为Java 9的两个固定大小的块。这样做的原因是,它将节省另一部分内存,以便移动所有内容并“压缩”仍在使用的内存。但是,由于您只是继续使用内存,因此在使用〜1/2内存时,它会立即中断。我不确定您可能对CS的要求多么严格,但是在我学校,我们研究了简单的垃圾处理技术,而G1GC令我想起的一种简单的垃圾处理技术是stop-and-copy技术,该技术可以在分配的内存的一半之间切换内存,同时“压缩”内存。
在Java 8中,使用了Parallel Collector,它与G1GC有所不同,因为它只关心吞吐量。因此,将使用接近100%的真实堆,但需要更长的GC时间。当然,这是两个版本之间的权衡,但是您可以通过明确指定要使用的GC的类型来解决此问题。例如,如果在Java 9上,则使用以下选项:
-XX:UseParallelGC
您应该看到与Java 8相同的行为。我链接的文章有所有不同的选项,但我认为您可以理解。希望这能帮助/回答您的问题,直到您提出该问题我才真正意识到这一点,因此感谢您使我意识到这一点。
编辑:根据Oracle自己,他们说新的G1垃圾收集器专用于高内存机器,这再次说明了为什么他们不会利用全部堆空间来花费GC-ing的时间更少。