Java进程的内存无限增长,但MemoryMXBean报告稳定的堆和非堆大小

时间:2016-08-24 08:05:17

标签: java linux memory memory-leaks

我正在与一个开发在1GB Linux目标系统上运行的Java GUI应用程序的团队合作。

我们遇到的问题是java进程使用的内存无限增长,直到Linux最终杀死java进程。

我们的堆内存健康稳定。 (我们已广泛地分析了我们的堆)我们还使用MemoryMXBean来监视应用程序的非堆内存使用情况,因为我们认为问题可能存在于那里。但是,我们看到报告的堆大小+报告的非堆大小保持稳定。

下面是一个示例,说明在我们的目标系统上运行具有1GB RAM的应用程序时的数字(MemoryMXBean报告的堆和非堆,使用Linux的top命令(驻留内存)监视的Java进程使用的总内存):

启动时:

  • 200 MB堆提交
  • 40 MB非堆提交
  • java进程使用的320 MB

1天后:

  • 200 MB堆提交
  • 40 MB非堆提交
  • java进程使用的360 MB

2天后:

  • 200 MB堆提交
  • 40 MB非堆提交
  • java进程使用的400 MB

上述数字只是我们系统执行情况的“清晰”表示,但它们相当准确且接近现实。如您所见,趋势很明显。运行应用程序几周后,由于系统内存不足,Linux系统开始出现问题。事情开始放缓。再过几个小时,Java进程就被杀了。

经过几个月的分析并试图理解这一点,我们仍然处于亏损状态。我觉得很难找到有关此问题的信息,因为大多数讨论最终都会解释堆或其他非堆内存池。 (像Metaspace等。)

我的问题如下:

  1. 如果你将其分解,java进程使用的内存包括什么? (除了堆和非堆内存池之外)

  2. 还有其他潜在的内存泄漏源吗? (本机代码?JVM开销?)一般来说哪些是最可能的罪魁祸首?

  3. 如何监控/分析此内存?堆+非堆外的所有内容目前对我们来说都是一个黑盒子。

  4. 非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

我会尝试部分回答你的问题。

我想在这种情况下坚持的基本策略是监控每个可用内存池的最大/已用/峰值,打开的文件,套接字,缓冲池,线程数,。可能会漏掉套接字连接/打开的文件/线程。

在你的情况下,看起来你真的遇到本机内存泄漏的问题,这是非常讨厌的,很难找到。

您可以尝试分析内存。查看transform(temp, rank_Var1= ave(Var1, Department, Product, FUN = function(x) rank(x, ties.method = "average"))) 个根,找出哪些是GC全局引用。它可以帮助您找出可能未收集哪些类。例如,这是JNI中的common problem,可能需要明确的组件处理。

要检查JVM内部内存使用情况(不属于堆/堆外内存) -XX:NativeMemoryTracking非常方便。它允许您跟踪线程堆栈大小,gc /编译器开销等等。最棒的是你可以在任何时间点创建一个基线,然后跟踪内存差异,因为基线已经完成

awt

您还可以使用# jcmd <pid> VM.native_memory baseline # jcmd <pid> VM.native_memory summary.diff scale=MB Total: reserved=664624KB -20610KB, committed=254344KB -20610KB ... JMX命令生成此报告。

并且......您可以更深入地检查pmap -x <pid>和/或procfs内容。

答案 1 :(得分:0)

我们似乎终于确定了问题的根本原因。这是特别导致该问题的答案,因为这对其他人来说并非不可能。

TLDR:

问题是由JDK中的一个错误导致的,现在已经修复了JDK 8u152。 Link to the bug report

整个故事:

在我第一次发布这个问题之后,我们继续监控应用程序的内存性能,而vsminkov建议的XX:NativeMemoryTracking极大地缩小了内存泄漏区域并确定了内容。

我们发现“Tread - Arenas”区域无限增长。由于这种泄漏是我们非常确定我们之前没有经历过的事情,我们开始使用早期版本的java进行测试,看看是否在某些特定点引入了它。

在回到java 8u73后,泄漏不存在,虽然被迫使用较旧的JDK版本并不是最佳的,但至少我们现在有办法解决问题。

几周后,在更新73上运行时,我们注意到应用程序仍在泄漏,我们再一次开始寻找罪魁祸首。我们发现问题现在位于Class - malloc区域。

此时我们几乎可以确定泄漏不是我们的应用程序的错误,我们正在考虑联系Oracle来报告该问题是一个潜在的错误,但是我的一位同事偶然发现了JDK热点编译器上的这个错误报告: Link to the bug report

错误描述与我们看到的非常相似。根据报告中的内容,自Java 8发布以来一直存在内存泄漏,并且在JDK 8u152的早期版本测试之后,我们现在相当确定泄漏是固定的。运行5天后,我们的应用程序的内存占用现在似乎接近100%稳定。类malloc区域仍然略有增长,但它现在以每天大约100 KB的速度增长(相比之前的几MB),并且仅测试了5天我无法确定它最终不会稳定

我不能肯定地说,但似乎我们与类malloc和Thread竞技场增长的问题是相关的。在任何一点上,这两个问题都在更新152中消失了。不幸的是,更新似乎没有安排在2017年底正式发布,但我们对早期版本的测试似乎很有希望到目前为止。