您可以使用-Xmx选项控制java中的最大堆大小.
我们正在使用此开关在Windows上遇到一些奇怪的行为.我们运行一些非常强大的服务器(想想196gb内存).Windows版本是Windows Server 2008R2
Java版本是1.6.0_18,64位(显然).
无论如何,我们遇到了一些奇怪的错误,其中进程因内存不足而退出,即使进程使用的内存少于-Xmx设置指定的内存.
所以我们编写了一个简单的程序,每次按下回车键就会分配一个1GB的字节数组,并将字节数组初始化为随机值(以防止任何内存压缩等).
基本上,最新的情况是,如果我们使用-Xmx35000m(大约35 gb)运行程序,当我们达到25 GB的进程空间(使用Windows任务管理器进行测量)时,我们会遇到内存不足的异常.我们在分配了24 GB的1 GB块(BTW)后点击这个,以便检出.
只需为-Xmx选项指定一个更大的值就可以使程序适用于更大量的ram.
那么发生了什么?是-Xmx只是"关闭".BTW:我们需要指定-Xmx55000m才能获得35 GB的进程空间......
关于发生了什么的任何想法?
他们是Windows JVM中的错误吗?
简单地将-Xmx选项设置得更大是否安全,即使-Xmx选项与进程明智之间存在脱节也是如此?
理论#1
当您使用-Xmx35000m请求35Gb堆时,您实际上所说的是允许堆使用的总空间为35Gb.但是总空间包括Tenured Object空间(对于存在多个GC周期的对象),新创建的对象的Eden空间以及垃圾收集期间将对象复制到的其他空间.
问题是某些空间不能用于分配新对象,也不能用于分配新对象.因此,实际上,您将35Gb中的很大一部分"丢失"到开销中.
有各种-XX选项可用于调整各个空格的大小等.您可以尝试摆弄它们以查看它们是否有所作为.有关更多信息,请参阅此文档.(常用的GC调整选项在第8节中列出.-XX:NewSpace选项看起来很有前景......)
理论#2
这可能会发生,因为您正在分配大型对象.IIRC,超过一定大小的对象可以直接分配到Tenured Object空间.在您的(高度人为的)基准测试中,这可能导致JVM没有将内容放入Eden空间,因此能够使用比正常情况更少的总堆空间.
作为一项实验,尝试更改基准以分配大量小对象,并查看它是否设法在OOME之前使用更多可用空间.
以下是我要打折的其他一些理论:
"你正在遇到操作系统强加的限制." 我会打折,因为你说通过增加-Xmx ...设置你可以获得更大的内存利用率.
"Windows任务管理器正在报告虚假号码." 我会对此进行折扣,因为报告的数字大致与您认为应用程序已设法分配的25Gb相匹配.
"你正在失去其他东西的空间;例如permgen堆." AFAIK,permgen堆大小的控制和计算独立于"正常"堆.其他非堆内存使用是一个常量(对于应用程序)或依赖于应用程序执行特定的事情.
"你正在遭受堆碎." 所有JVM垃圾收集器都是"复制收集器",这个收集器系列具有自动压缩堆节点的属性.
"Windows上的JVM错误." 不大可能.Windows安装上必须有数万个64位Java才能最大化堆大小.别人会注意到......
最后,如果你不这样做是因为你的应用程序要求你以巨大的块分配内存,并且"永远"挂在它上面......你很有可能追逐阴影."普通"大内存应用程序不会执行此类操作,并且JVM针对正常应用程序进行了调整...而不是异常应用程序.
如果您的应用程序确实以这种方式运行,那么实用的解决方案就是将-Xmx ...选项设置得更大,并且只有在您开始遇到操作系统级问题时才会担心.