当我把这个情况描述给工程师的时候,有一位工程师觉得很有意思,因此写了个小的测试用例来重现了这个问题。你可以在Linux下编译并运行下面这个代码片段(我是在最新的稳定版Ubuntu上运行的)。
package eu.plumbr.demo;
publicclass OOM {
publicstaticvoid main(String[] args){
java.util.List l =new java.util.ArrayList();
for(int i =10000; i <100000; i++){
try{
l.add(newint[100_000_000]);
}catch(Throwable t){
t.printStackTrace();
}
}
}
}
然后你就会发现同样的一个 Out of memory: Kill process (java) score or sacrifice child信息。
注意的是,你可能得调整下交换分区以及堆的大小,在我这个测试用例中,我通过-Xm2g设置了2G大小的堆,同时交换内存使用的是如下的配置:
swapoff -a
dd if=/dev/zero of=swapfile bs=1024 count=655360
mkswap swapfile
swapon swapfile
解决方案?这种情况有好几种解决方案。在我们这个例子中,我们只是把系统迁移到了一台内存更大的机器上(裤子都脱了就让我看这个?)我也考虑过激活交换分区,不过咨询了工程师之后我想起来JVM上的GC进程在交换分区下的表现并不是很理想,因此这个选项就作罢了。
还有别的一些方法比如OOM killer的调优,或者将负载水平分布到数个小的实例上,又或者减少应用程序的内存占用量。