【问题标题】:java process consumes more memory over time but no memory leak [duplicate]java进程随着时间的推移消耗更多内存但没有内存泄漏[重复]
【发布时间】:2020-11-06 07:04:56
【问题描述】:

我的 java 服务在 16 GB RAM 主机上运行,​​ -Xms 和 -Xmx 设置为 8GB。 主机正在运行其他几个进程。

我注意到我的服务随着时间的推移会消耗更多的内存。 我在主机上运行了这个命令ps aux | awk '{print $6/1024 " MB\t\t" $11}' | sort -n,并记录了我的java服务的内存使用情况。

服务启动时,它使用了大约 8GB 内存(因为 -Xms 和 -Xmx 设置为 8GB),但一周后,它使用了大约 9GB+ 内存。它每天消耗大约 100MB 的内存。

我做了一个堆转储。我重新启动了服务并进行了另一个堆转储。我比较了这两个转储,但堆使用量没有太大差异。转储显示该服务在重启前使用了大约 1.3GB,在重启后使用了大约 1.1GB。

从进程内存使用情况来看,我的服务随着时间的推移消耗了更多内存,但堆转储中没有报告。如何识别服务中内存使用量的增加?

我将 -Xms 和 -Xmx 设置为 8GB。主机有 16GB 内存。我是否将最小/最大堆设置得太高(主机上总内存的 50%)?这会导致任何问题吗?

【问题讨论】:

    标签: java memory-leaks jvm


    【解决方案1】:

    好的,所以您已经告诉 JVM,它最多可以使用 8GB 的​​堆,并且您观察到 total 内存使用量从 1.1GB 增加到 1.3GB。这实际上并不是一个迹象或问题本身。当然,JVM 并没有像你所说的那样使用任何地方的内存。

    要注意的第二件事是,您不清楚如何测量内存使用情况。您应该知道 JVM 使用大量内存,而不是 Java 堆内存。这包括:

    • java 可执行文件本身使用的内存。
    • 用于保存本机库的内存。
    • 用于保存字节码和 JIT 编译的本机代码的内存(在“元空间”中)
    • 线程堆栈
    • (通常)本机代码请求的堆外内存分配。
    • 内存映射文件和共享内存段。

    报告了其中的一些用法(如果您使用正确的工具)。

    第三件事是Java堆实际使用的内存可以变化很大。 GC 通常通过将活动对象从一个“空间”复制到另一个来工作,因此它需要大量的可用空间来执行此操作。然后,一旦完成运行,GC 就会查看(现在)有多少可用空间与已用空间的比率。如果该比率太小,它会向操作系统请求更多内存。因此,即使实际使用量(在非垃圾对象中)只是逐渐增加,总内存使用量也可能会大幅增加。由于各种“热身”效应,这对于最近才启动的 JVM 来说很有可能。

    最后,您提供的证据并没有说(对我来说!)没有内存泄漏。我认为您需要将堆转储进一步分开。我建议在启动后 2 小时进行一次转储,然后在 2 小时或更长时间后进行第二次转储。这会给你足够的“泄漏”来显示在转储比较中。

    从进程内存使用情况来看,我的服务随着时间的推移消耗更多内存,但堆转储中没有报告。如何识别服务中内存使用量的增加?

    我认为你不需要这样做。我认为总体内存使用量从 1.1GB 增加到 1.3GB 是一个红鲱鱼。

    相反,我认为您应该关注其他证据所指向的内存泄漏。请参阅我上面的建议。

    我是否将最小/最大堆设置得太高(主机上总内存的 50%)?这会导致任何问题吗?

    嗯……当堆满时,更大的堆会导致更明显的性能下降。另一方面,更大的堆意味着填充需要更长的时间......假设您有内存泄漏......这意味着诊断问题可能需要更长的时间,或者确保您已修复它。

    但另一方面,这可能根本不是内存泄漏。它也可能是您的应用程序或第三方库缓存的东西。正确实现的缓存可能会使用大量内存,但如果堆太接近满,它应该通过断开链接1 并清除缓存数据来做出响应。因此,不是内存泄漏......假设。


    1 - 或者如果你使用SoftReferences,GC 会为你破解它们。

    【讨论】:

      猜你喜欢
      • 2019-01-25
      • 1970-01-01
      • 2011-11-14
      • 2018-01-14
      • 1970-01-01
      • 2018-03-01
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      相关资源
      最近更新 更多