Java-Xmx在大量ram上的怪异行为

Java-Xmx在大量ram上的怪异行为,java,windows,Java,Windows,您可以使用-Xmx选项控制java中的最大堆大小 我们在Windows上使用此开关时遇到一些奇怪的行为。我们运行一些非常强大的服务器(比如196gb的ram)。Windows版本是Windows Server 2008R2 Java版本是1.6.0_18,64位(显然) 无论如何,我们遇到了一些奇怪的错误,进程退出时出现内存不足异常,尽管进程使用的内存比-Xmx设置指定的要少得多 因此,我们编写了一个简单的程序,每次按enter键时分配一个1GB的字节数组,并将字节数组初始化为随机值(以防止任何

您可以使用-Xmx选项控制java中的最大堆大小

我们在Windows上使用此开关时遇到一些奇怪的行为。我们运行一些非常强大的服务器(比如196gb的ram)。Windows版本是Windows Server 2008R2

Java版本是1.6.0_18,64位(显然)

无论如何,我们遇到了一些奇怪的错误,进程退出时出现内存不足异常,尽管进程使用的内存比-Xmx设置指定的要少得多

因此,我们编写了一个简单的程序,每次按enter键时分配一个1GB的字节数组,并将字节数组初始化为随机值(以防止任何内存压缩等)

基本上,如果我们使用-xmx3500M(大约35GB)运行程序,当我们达到25GB的进程空间时(使用windows任务管理器测量),就会出现内存不足异常。顺便说一句,我们是在分配了价值24 GB的1 GB块后实现这一点的,所以这是正确的

只需为-Xmx选项指定一个更大的值,程序就可以在更大数量的ram中正常工作

那么,到底发生了什么?Is-Xmx只是“关闭”。顺便说一句:我们需要指定-xmx5500M以获得35 GB的进程空间

有什么想法吗

它们是Windows JVM中的一个bug吗


简单地将-Xmx选项设置得更大是否安全,即使-Xmx选项与进程之间存在断开连接?

我认为这与堆的碎片化有关。可用内存可能无法作为单个连续可用区域使用,当您尝试分配一个大数据块时,这会失败,因为请求的内存无法在单个数据块中分配。

要了解您正在测量的内容,您应该使用一些不同的工具:

  • Windows任务管理器(我只知道Windows XP,但我听说任务管理器从那时起有所改进。)
  • 来自系统内部的
    procep
    vmmap
  • jconsole来自JVM(您正在使用SunOracleHotSpot JVM,不是吗?)
  • 现在,您应该回答以下问题:

    • 关于使用的堆大小,
      jconsole
      怎么说?这与
      procexp
      有何不同
    • 如果用非零数字填充字节数组而不是将其保持在
      0
      ,则
      procep
      中的值是否会更改

    windows任务管理器显示的内存是分配给进程的总内存,包括代码、堆栈、perm gen和堆的内存。 使用click程序测量的内存是jvm为运行jvm程序提供的堆内存量。
    通常,windows分配给JVM的总内存应该大于JVM作为堆内存提供给您的程序的内存。

    您是否尝试打开GC的详细输出以找出上次分配失败的原因。这是因为操作系统无法为本机JVM进程分配超过25GB的堆,还是因为GC在其可以管理的最大内存上遇到某种限制。我建议您也使用jconsole连接到命令行进程,以查看在分配失败之前堆的状态。此外,sysinternals process explorer之类的工具可能会提供更好的详细信息,说明故障发生在jvm进程中的何处

    由于进程将以25GB的速度消亡,并且您有一个分代收集器,因此其他几代可能会消耗10GB。我建议您安装JDK 1.6_u24,并将jvisualvm与visualGC插件一起使用,以了解GC正在做什么,尤其是考虑到所有代的大小,以了解35GB堆是如何被GC/VM内存管理器分割成不同的区域的

    如果您不熟悉世代GC理论,请参见此链接

    当您使用-xmx3500M请求35Gb堆时,您实际说的是允许堆使用的总空间为35Gb。但总空间由永久对象空间(对于在多个GC循环中存活的对象)、新创建对象的Eden空间以及在垃圾收集期间将对象复制到其中的其他空间组成

    问题在于,某些空间不是也不能用于分配新对象。因此,实际上,35Gb的很大一部分“损失”在日常开支上

    有各种-XX选项可用于调整相应空格的大小,等等。您可以尝试摆弄它们,看看它们是否有不同。有关更多信息,请参阅。(第8节列出了常用的GC调优选项,-XX:NewSpace选项看起来很有希望……)


    理论#2

    这可能是因为您正在分配巨大的对象。IIRC,超过一定大小的对象可以直接分配到终身对象空间。在您的(高度人工的)基准测试中,这可能会导致JVM没有将内容放入Eden空间,因此能够使用比正常情况更少的总堆空间

    作为一个实验,试着改变你的基准来分配大量的小对象,看看它是否能在OOME之前使用更多的可用空间


    以下是一些我不太认同的其他理论:

    • “您正在运行操作系统强加的限制。”我不认为这一点,因为您说过通过增加-Xmx可以获得更大的内存利用率。。。背景

    • “Windows任务管理器报告的数字是假的。”我不认为这是因为报告的数字与您认为应用程序已设法分配的25Gb大致相符

    • “您正在向其他对象丢失空间,例如permgen堆。”好的,permgen堆的大小是独立于“正常”堆控制和计算的。其他非堆内存使用是常量(对于