首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java进程内存使用量一直在无限增长

Java进程内存使用量一直在无限增长
EN

Stack Overflow用户
提问于 2016-11-18 16:30:03
回答 3查看 7.2K关注 0票数 23

前提条件:

安装在Ubuntu16.10 x64上的

  • PC和16 Gb内存的
  • JDK 1.8.x。
  • 是一个标准的基于Spring的web应用程序,部署在Tomcat8.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堆内存使用的running
  • JProfiler 9.x用于java进程内存使用跟踪的tracking
  • top

当我连续3次启动负载测试时,我观察到(使用top) java进程正在增加已用内存的数量:

  • 在Tomcat启动后,它使用大约1 7Gb的
  • 在第一次测试运行后,它使用4.5 7Gb的
  • 在所有测试完成后,Tomcat使用7 7Gb的内存

所有这段时间的堆大小是有限的,并且JProfiler确认-堆大小不超过512Mb。

这是JProfiler的屏幕截图。底部的红色数字表示java进程使用的内存大小(根据top)。

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

谢谢!

关于可能的重复版本: they have confirmed that this only happens on Solaris.,但我用的是Ubuntu16.10。同样,尖锐的问题也没有一个可以解释问题原因的答案。

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

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

我将感谢任何关于这个问题的提示。谢谢大家!

jemalloc更新#3:使用jemalloc(感谢@ivan的想法)我得到了下一张图片:

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

Java.util.zip.inflater/:现在我发现这个问题与java.util.zip.Inflater/Deflater有关,这些类在我的应用程序的许多地方使用。但对内存消耗影响最大的是使用remove SOAP-service进行交互。我的应用程序使用JAX-WS标准的参考实现,它给出了负载下的下一次内存消耗(它在10 it之后的精度较低):

然后我做了同样的负载测试,但是使用了Apache CXF实现,结果如下:

所以您可以看到,CXF使用的内存更少,而且更稳定(它并不像ref.impl一样一直在增长)。最后,我发现了一个关于JDK问题跟踪器的问题-- https://bugs.openjdk.java.net/browse/JDK-8074108 --同样是关于压缩库中的内存泄漏,这个问题还没有解决。因此,看起来我不能真正修复我的应用程序中的内存泄漏问题,只能做一些变通。

感谢大家的帮助!

EN

回答 3

Stack Overflow用户

发布于 2016-12-17 17:14:02

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

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

我以前有过一台similar case

票数 5
EN

Stack Overflow用户

发布于 2016-12-21 05:19:41

你能用这个选项-XX:MaxDirectMemorySize=1024m重新运行你的测试吗?这个限制的精确值并不重要,但它显示了可能的“泄漏”。

您还可以提供GC详细信息(-XX:+PrintGC)吗?

java.nio.ByteBuffer可能是导致这些问题的原因之一,因为它是特定的最终结果。

更新#1

出于另外两个原因,我也看到了类似的行为: java.misc.Unsafe (不太可能)和高负载的JNI调用。

如果没有测试的简介,就很难理解。

更新#2

高负载的JNI调用和finalize()方法都会导致上述问题,因为对象没有足够的时间来完成。

下面是j.u.zip.Inflater片段:

代码语言:javascript
复制
/**
 * Closes the decompressor when garbage is collected.
 */
protected void finalize() {
    end();
}

/**
 * Closes the decompressor and discards any unprocessed input.
 * This method should be called when the decompressor is no longer
 * being used, but will also be called automatically by the finalize()
 * method. Once this method is called, the behavior of the Inflater
 * object is undefined.
 */
public void end() {
    synchronized (zsRef) {
        long addr = zsRef.address();
        zsRef.clear();
        if (addr != 0) {
            end(addr);
            buf = null;
        }
    }
}

private native static void end(long addr);
票数 1
EN

Stack Overflow用户

发布于 2016-12-20 16:53:25

基于Occam的剃刀:会不会是你的某个地方有内存泄漏(例如,“非故意的对象保留”a‘’la Java Item 6)?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40672443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档