【问题标题】:JVM memory inconsistencies on HerokuHeroku 上的 JVM 内存不一致
【发布时间】:2021-08-10 02:45:10
【问题描述】:

我有一个应用程序在 Heroku 上托管在一个具有 1GB RAM 的单个测功机上。我观察到关于记忆的奇怪行为。当我的应用程序正在使用时,我注意到测功机上消耗的总内存继续随着负载/使用而增加(这会尖叫内存泄漏,但稍后会看到......)但在垃圾收集运行时永远不会回落。我可以在我的 JVM 图表中看到 JVM 定期回收堆空间,但我从未看到总内存使用量相应减少;它似乎只会增加。

见下图:

我使用 Eclipse MAT 分析了一个堆转储,但没有发现任何说明。此外,我还向 JVM 添加了参数,如 here 所述,以将 JVM 的目标内存消耗绑定到容器而不是服务器本身。

如果有人能指出正确的方向,为什么 Heroku 报告的测功内存与我在 JVM 的堆和非堆空间图上看到的不一致,将不胜感激。

【问题讨论】:

    标签: java heroku memory jvm


    【解决方案1】:

    您的 Java 代码中可能存在内存泄漏,但证据并不确凿。

    但如前所述,内存使用情况的外部(dymo)报告必然不同于内部(JVM 堆)报告:

    1. 在 GC 运行后,JVM 往往不会将内存归还给操作系统。它倾向于保留内存……以便可以将新对象放入其中。

    2. JVM 使用不属于常规堆的内存。

    3. 其他进程的内存使用情况将包含在dymo报告中(很明显)。

    现在,如果您的 JVM 内存图显示波谷底部的水平随时间持续增加,这将是(可能的)内存泄漏的强烈迹象。特别是如果堆使用峰值经常接近您配置的 JVM max_heap。然而:

    • 图表显示的数据不足,无法得出任何结论
    • 如果堆没有变满,您将不会触发 WeakReferences 的中断,因此 GC 感知缓存可能会被填满。 (这可能很好,也不错。)

    最后,如果我正确地阅读了图表,你有大约 1GB 的可用 RAM,并且你正在运行 JVM,最大堆为 1GB。这是自找麻烦。

    (如果您的 JVM 导致虚拟内存抖动,它很可能会被操作系统的 OOM 杀手杀死。或者更糟......它可能会杀死其他一些更重要的进程。)

    【讨论】:

    • 谢谢!我指定的最大堆大小为 -Xmx671m,所以我认为堆图显示 1GB 只是为了让所有图上的 y 轴都匹配。我并没有真正考虑过 JVM 保留它已经从操作系统中获取的内存,但这是有道理的。但是,然后我希望测功机最大内存等于最大堆内存(自上次重启以来的任何时间)+ 最大非堆内存(自上次重启以来的任何时间),但它似乎比这还要高。我知道还有其他进程正在运行,例如内存监视器等,但我认为它们不会那么耗内存。
    【解决方案2】:
    jvm-level 中的

    垃圾收集(它标记可用于其他对象的内存)但第一个图(内存使用情况)是操作系统级别。 容器在垃圾回收时不必将内存释放回操作系统。总使用量可能不会因堆使用量而减少,但如果不收集它可能会超出限制。

    上午 10:30,您的堆变大了,您的操作系统级别的使用量增加了,并且没有返还它所占用的资源。

    您还可以将 xms 和 xmx 定义为相同,这可能会更有效,只是不要忘记您的限制不仅仅是堆大小,还有其他东西。如栈、寄存器等

    驻留内存 (memory_rss):测功机内存(兆字节)中保存在 RAM 中的部分。 https://devcenter.heroku.com/articles/log-runtime-metrics#memory-swap

    【讨论】:

      猜你喜欢
      • 2012-09-08
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      相关资源
      最近更新 更多