Heroku 上的 JVM 内存不一致

JVM memory inconsistencies on Heroku

我有一个应用程序在 Heroku 上托管在一个具有 1GB RAM 的单个测功机上。我正在观察关于记忆的奇怪行为。当我的应用程序被使用时,我注意到 dyno 上消耗的总内存继续增加 load/usage(这表明内存泄漏但稍后会看到......)但是当垃圾收集运行时永远不会恢复。我可以在我的 JVM 图表中看到堆 space 经常被 JVM 回收,但我从未看到总内存使用量相应减少;它似乎只会增加。

见下图:

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

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

jvm-level 中的垃圾收集(它标记内存可用于其他对象)但第一张图(内存使用情况)是OS级。 容器在被垃圾收集 时不必将内存释放回OS。总使用量可能不会因堆使用量而减少,但如果不收集它可能会突破限制。

在 10:30AM,你的堆变大了,你的 OS 级使用率增加了,但没有回馈它所花费的。

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

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

您的 Java 代码中可能存在内存泄漏,但证据尚无定论。

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

  1. JVM 往往不会在 GC 运行 之后将内存返回给 OS。它倾向于保留内存...以便可以将新对象放入其中。

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

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

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

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

最后,如果我没看错图表,您将有大约 1GB 的空闲 RAM,并且您正在 运行使用 1GB 的最大堆连接 JVM。那是自找麻烦

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