Java进程内存使用量不断增加

标签 java tomcat memory

前提条件:

  • 具有 16 Gb 内存的电脑
  • JDK 1.8.x 安装在 Ubuntu 16.10 x64 上。
  • 一个标准的基于 Spring 的 Web 应用程序,部署在 Tomcat 8.5.x 上。 Tomcat 配置了下一个参数: CATALINA_OPTS="$CATALINA_OPTS -Xms128m -Xmx512m -XX:NewSize=64m -XX:MaxNewSize=128m -Xss512k -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX :MaxMetaspaceSize=512m -XX:-TieredCompilation -XX:ReservedCodeCacheSize=512m"
  • 用于运行负载测试的 JMeter 2.13
  • 用于 Java 堆内存使用跟踪的 JProfiler 9.x
  • top java 进程内存使用跟踪工具

当我按顺序开始负载测试 3 次时,我观察到(使用 top)java 进程正在增加已用内存的数量:

  • Tomcat 启动后使用 ~1Gb
  • 第一次测试运行后,它使用 4.5Gb
  • 当所有测试完成后,Tomcat 正在使用 7Gb 的 RAM

一直以来堆大小是有限的,JProfiler 确认 - 堆大小不超过 512Mb。

这是 JProfiler 的截图。底部的红色数字是java进程使用的内存大小(根据top)。 enter image description here

问题是:为什么 java 进程在工作时总是不断增加内存使用量?

谢谢!

UPD#1:关于可能的重复:他们已确认这只发生在 Solaris 上。 但我使用的是 Ubuntu 16.10。同样,指出的问题也没有可以解释问题原因的答案。

UPD#2:我不得不在停顿后回到这个问题。现在我使用 pmap 工具来转储 java 进程使用的内存。我有三个转储:在测试运行之前,在第一次测试执行之后和在一些 N 测试执行之后。测试它们会为应用程序产生大量流量。所有转储都在这里:https://gist.github.com/proshin-roman/752cea2dc25cde64b30514ed9ed9bbd0 .它们非常大,但最有趣的是第 8 行的堆大小:测试前需要 282.272 Kb,最后需要 3.036.400 Kb - 差异超过 10 倍!每次我运行测试时它都在增长。同时堆大小是恒定的(根据 JProfiler/VisualVM)。我有什么选择可以找到这个问题的原因?调试JVM?我试图找到任何方法来“查看”这段内存,但失败了。所以:

  • 我能以某种方式识别 [heap] 内存段的内容吗?
  • java 的这种行为看起来是预期的吗?

我将不胜感激有关此问题的任何提示。谢谢大家!

UPD #3:使用 jemalloc(感谢@ivan 的想法)我得到了下一张图片: enter image description here

看起来我遇到了与此处描述的几乎相同的问题:http://www.evanjones.ca/java-native-leak-bug.html

UPD #4:目前我发现该问题与 java.util.zip.Inflater/Deflater 有关,并且这些类在我的应用程序的许多地方都使用过。但是对内存消耗的最大影响是与删除 SOAP 服务的交互。我的应用程序使用 JAX-WS 标准的引用实现,它在负载下给出了下一个内存消耗(在 10Gb 之后它具有低精度):memory consumption with reference implementation 然后我进行了相同的负载测试,但使用了 Apache CXF 实现,它给出了下一个结果:memory consumption with Apache CXF 所以你可以看到 CXF 使用更少的内存并且更稳定(它并没有像 ref.impl. 那样一直在增长)。 最后我在 JDK 问题跟踪器上发现了一个问题 - https://bugs.openjdk.java.net/browse/JDK-8074108 - 这又是关于 zip 库中的内存泄漏,问题还没有解决。所以看起来我无法真正解决我的应用程序中的内存泄漏问题,只能做一些解决方法。

感谢大家的帮助!

最佳答案

我的假设是您在 JProfiler 中收集分配信息/调用堆栈等,而您观察到的 RSS 增长与 JProfiler 将该数据保存在内存中有关。

您可以通过收集较少的信息来验证这是否属实(分析开始时应该有一个屏幕允许您例如不收集对象分配),并查看您是否观察到结果是较小的 RSS 增长。不使用 JProfiler 运行负载测试也是一种选择。

我有一个 similar case在过去。

关于Java进程内存使用量不断增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40672443/

相关文章:

java - Intellij 中无法识别“Javac”错误

java - Rx 将 Observable<List<T>> 转换为 Observable<T>

java - websocket 发送期间 ByteBuffer 中的 IllegalArgumentException

java - 写JSP代码在tomcat服务器上运行时,没有任何显示

java - 在 Tomcat 8.5 上找不到 liquibase.logging.Logger 的实现

android - Android应用程序的标准内存覆盖率

在 char *pointer 上尝试 strcpy 时出现 C 段错误

Java泛型?

Java 打印杂散字符而不是实际字符

c - 为包装在 C 中的结构中的二维指针数组分配内存