JVM应用程序内存占用与OS内存之间的差异

JVM应用程序内存占用与OS内存之间的差异

我知道这是一个已经讨论过的问题,但我找不到让自己内心平静的方法。

基本上,我们有一个在 tomcat 应用程序服务器下运行的 java web 应用程序,具体来说:

  • Java HotSpot(TM) 64 位服务器 VM;1.8.0_112;25.112-b15;混合模式
  • Tomcat 7.0_Tomcat7.0.73
  • Windows Server 2012 R2(6.3.9600)

我们的应用程序占用太多内存,因此我们开始对其进行分析;但我无法理解应用程序内存消耗(堆/非堆)和操作系统内存之间的简单区别:

Yourkit 分析器:

堆和非堆内存使用情况

这里的内存是 4.1 Gb(堆已提交)加上 660 Mb(非堆,因此是元空间、代码缓存、压缩类空间),所以共计 4.7 Gb

Windows 内存:

在此处输入图片描述

我在这里看到6.266 GBTomcat 进程实际使用的内存量

我怎样才能测量这 1.5 Gb 的差异?

它只针对 Tomcat 应用程序本身吗?JVM 运行时呢?如果是,我该如何测量它?

编辑:在应用程序服务器(Tomcat)启动后,这种差异似乎随着时间的推移而增长;最初,堆/非堆的总和非常接近操作系统记录的 Tomcat 进程使用的内存,然后在几小时/几天后趋于增长。

编辑2:Tomcat 服务器中的 JAVA 选项

-Xms512m
-Xmx6144m
-Dlog=production
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-Djava.util.Arrays.useLegacyMergeSort=true
-Duser.country=IT
-Duser.language=it
-XX:+UseG1GC
-XX:+UseStringDeduplication

谢谢

答案1

Java 分配堆和 Windows 工作集并不完全相同。

1.5 GB 的差异是由于 Windows 上内存的寻址方式造成的。为了解释这一点,以下是我认为最相关的事实:

  • ‘xmx’ 为 6 GB
  • 您使用的是 Windows
  • 图表中的“限制”是 5.3 GB。
  • 只有在服务器运行几天后才会看到此情况

在 Windows 上,JVM 需要一块连续的虚拟内存用于堆。应用程序启动时,它将寻址 6 GB,但仅物理分配您最初为“xms”设置的值。随着应用程序的运行,它最终将为堆分配更多内存,最高可达 6 GB 减去非堆内存所需的内存(例如 Java 8+ 的 Metaspace)。非堆内存应基本保持在 660 MB 不变,除此之外,JVM 本身可能还有一些额外的内存(我想是 128 MB?)。

您的配置文件中的图表显示当前已分配 4.1 GB,但限制为 5.3 GB。我相信“限制”是堆可用的最大空间量,应该等于“xmx”值减去元空间。由于要求 Java 堆具有连续的内存块,因此很有可能该限制值的 100% 被报告为已提交给操作系统。

5.3 GB + 660 MB = 5960+ MB(可能更多,具体取决于限制的四舍五入方式)。如果我们猜测它实际上等于 xmx 值 6144,那么 JVM 的 128 MB = 6272 MB,这比 Windows 所说的私有的 6266 MB 稍微多一点。

剩下的唯一问题是...如果“xms”设置为 512 MB,为什么 JVM 会物理寻址整个可用堆?答案是因为它认为出于某种原因需要物理寻址整个堆。显然,在您对其进行分析时,它不会这样做,但是当它进行垃圾收集时,您的图表中会出现相当大的下降(例如一次释放 1 GB?)对此的标准答案是:

  • 你可能存在内存泄漏 - 该图看起来很可疑
  • 也许 JVM 因为某些您不知道的很好的理由而需要更多的 RAM(例如重负载)。

但是,一旦 JVM 实际物理分配了 RAM,它就很少会将其归还。它可以,而且使用 G1GC 时,它应该比其他垃圾收集器更频繁地归还 RAM,但您不应该假设操作系统看到的工作集实际上会减少。

相关内容