Java 为什么JMX报告的JVM堆最大使用率会随着时间的推移而变化?

Java 为什么JMX报告的JVM堆最大使用率会随着时间的推移而变化?,java,jvm,heap,Java,Jvm,Heap,我的JVM heap max在我的一个hadoop集群的名称节点上配置为8GB。当我使用JMX监控JVM时,报告的最大值不断波动,如所附图像所示 我只在我的hadoop集群中的一个(最活跃的)集群上看到这种行为。在其他集群上,报告的最大值保持固定在配置值。知道为什么报告的最大值会改变吗 更新: java版本是“1.6.0_20” heap max值在hadoop-env.sh中通过以下行设置: export HADOOP\u NAMENODE\u OPTS=“-Xmx8G-Dcom.sun.m

我的JVM heap max在我的一个hadoop集群的名称节点上配置为8GB。当我使用JMX监控JVM时,报告的最大值不断波动,如所附图像所示

我只在我的hadoop集群中的一个(最活跃的)集群上看到这种行为。在其他集群上,报告的最大值保持固定在配置值。知道为什么报告的最大值会改变吗

更新:

java版本是“1.6.0_20”

heap max值在hadoop-env.sh中通过以下行设置:

export HADOOP\u NAMENODE\u OPTS=“-Xmx8G-Dcom.sun.management.jmxremote.port=8004$JMX\u SHARED\u PROPS”

ps显示:

hadoop 27605 1999年7月30日?11-07:23:13/usr/lib/jvm/jre/bin/java-Xmx1000m-Xmx8G

更新2:

昨晚在启动命令行中添加了
-Xms8G
开关:

export HADOOP_NAMENODE_OPTS=“-Xms8G-Xmx8G-Dcom.sun.management.jmxremote.port=8004$JMX_SHARED_PROPS”

如下图所示,最大值仍在变化,尽管模式似乎已改变

更新3:

下面是一个新的图表,它还显示了保持不变的非堆最大值:

根据文档,内存使用情况分为两类,“堆”和“非堆”内存。非堆类别的描述说明如下:

Java虚拟机管理堆以外的内存(称为非堆内存)。 Java虚拟机有一个在所有线程之间共享的方法区域。方法区域属于非堆内存。它存储每类结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码。它是在Java虚拟机启动时创建的

方法区域在逻辑上是堆的一部分,但是Java虚拟机实现可以选择不进行垃圾收集或压缩。与堆类似,方法区域可以具有固定大小,也可以扩展和收缩。方法区域的内存不需要是连续的

这一描述听起来很像永久生成(PermGen),它实际上是堆的一部分,并根据使用
-Xmx
标志分配的内存计数。我不知道他们为什么决定单独报告,因为这是堆的一部分


我怀疑您看到的波动是JVM收缩和增加永久生成的结果,这将导致报告的可用于非永久使用的最大堆空间发生相应的变化。如果您可以得到JMX报告的堆和非堆最大值的总和,并且该总和在8G限制下保持不变,这将验证这一假设。

一种可能性是JVM生存空间在最大大小上波动

JMX通过HeapMemoryUsage.max属性报告的JVM最大大小不是堆的实际最大大小(即设置为-Xmx的大小)

报告的值是最大堆大小减去最大幸存者空间大小

要获取总最大堆大小,请添加两个jmx属性:

java.lang:type=Memory/HeapMemoryUsage.max + java.lang:type=MemoryPool,name=Survivor Space/Usage.max

(在oracle jdk 1.7.0_45上测试)

我怀疑此节点上没有设置max。如果未设置,JVM将决定使用多少。什么是java版本?我用java版本和max设置更新了这个问题。ps为Xmx显示了两个值——在所有集群上都是这样。第二个值似乎是正在使用的值。您是否尝试设置Xms以查看它是否有任何更改?尚未尝试Xms,但我会尝试一下。这是一个生产集群,所以我不能经常重启。
-Xmx1000m-Xmx8G
-Xmx1000m
来自哪里?是否与其他命令行相同?我添加了另一个图形以显示非堆最大值。正如你所看到的,它保持不变,所以我认为它不是永久性的。另外,我没有看到堆最大值在任何其他集群上变化,只有这一个。哦,好吧,这是一个很好的猜测。我可以想到的其他场景:(a)如果JVM能够检测到并非所有配置的数量都可以从操作系统获得,那么报告的最大值可能会小于您的配置值,或者(b)heap max被计算为各个GC代的最大值之和,其单个最大值可能不占全部8GB。但这都是猜测。实际上是擦伤(a),因为您从-Xms开始,它应该在启动时从操作系统请求完整的8GB。