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

标签 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 进程被杀死。

经过几个月的分析并试图弄明白这一点,我们仍然不知所措。我觉得很难找到有关此问题的信息,因为大多数讨论最终都解释了堆或其他非堆内存池。 (如元空间等)

我的问题如下:

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

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

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

任何帮助将不胜感激。

最佳答案

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

在这种情况下,我试图坚持的基本策略是监控每个可用内存池、打开的文件、套接字、缓冲池、线程数等的最大/使用/峰值。您可能会错过套接字连接/打开的文件/线程的泄漏。

在您的情况下,您似乎确实遇到了 native 内存泄漏问题,这非常令人讨厌且难以找到。

您可以尝试分析内存。看看GC根并找出哪些是JNI全局引用。它可以帮助您找出哪些类可能没有被收集。例如,这是一个 common problemawt这可能需要明确的组件处置。

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

# jcmd <pid> VM.native_memory baseline
# jcmd <pid> VM.native_memory summary.diff scale=MB

Total:  reserved=664624KB  -20610KB, committed=254344KB -20610KB
...

您也可以使用JMX com.sun.management:type=DiagnosticCommand/vmNativeMemory生成此报告的命令。

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

关于Java 进程的内存无限增长,但 MemoryMXBean 报告稳定堆和非堆大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39117716/

相关文章:

java - 将 AspectJ 与 iBatis、Spring 结合使用时不应用事务

java - SWT在windows上哪里写dll文件?

java - Primefaces p :autcomplete issues with String field in POJO

linux - 如果文件的大小超过了文件系统的最大大小,会发生什么?

java - 使内存限制成为构建过程一部分的强大策略是什么?

memory - 超大型项目的最佳 CLion VM 内存设置

java - 如何在 Java 中将 blob 格式的图像保存到 MySQL

linux - 在 shell 脚本中创建结构(数据结构)

linux - 如何从 gz 文件中提取特定文本?

c - 在 qemu 中打印内存地址范围