java - JConsole 堆转储比内存使用量小得多

标签 java linux spring-boot

我们有一些使用 docker 运行 java 进程的容器。我们一直注意到的一件事是,仅通过运行一个简单的 spring-boot 应用程序就占用了大量内存,甚至没有包含我们自己的代码(只是为了尝试获得某种内存配置文件,而不受我们可能引入的任何问题的影响) ).

我看到的是 docker/JVM 消耗的内存在 2.5 左右徘徊。我们确实在其中包含了相当数量的额外依赖(camel、hibernate、一些 spring-boot 依赖),但这并不是真正让我失望的原因。我看到的是,尽管 docker 说它为应用程序消耗了 2.5GB 的内存,但针对它运行 jconsole 读取它消耗了高达 1GB(在 GC 之后下降到 ~200MB 并且缓慢攀升)。 docker 上的内存占用也保持在 GC 之后的位置(2.5GB)。

此外,当我转储堆以查看哪些类型的对象正在占用该空间时,在我将 .hprof 文件加载到 MAT 后,堆看起来只有 33MB 大。这些对我来说都没有多大意义。目前,我正在查看 jconsole 中报告的非堆空间为 115MB,而堆空间为 331MB。

我已经(在 SO 和其他网站上)阅读了大量关于 JVM 内存区域的文章,以及一些专门报告堆转储可能更小的内容,但它们都不是我能说的这么远,除此之外,许多建议要注意的事情是,只要进行堆转储,GC 就会运行,并且 MAT 有一个设置来显示或隐藏无法访问的对象。所有这些在发帖之前都已考虑在内,现在我只是觉得有其他事情在起作用,我无法捕捉到自己,而且我还没有在网上找到。

我完全预计这些数字可能会有点偏差,但在最好的情况下它们偏差了 10 倍,而在查看 docker 报告的内存使用情况时偏差了近 100 倍,这似乎是极端的.

有谁知道我在这里可能遗漏了什么?

编辑:这也是一个使用 Java 8 运行的应用程序,尚未使用 Java 11 运行。它在 JIRA 板上要做,但尚未计划。

EDIT2:添加屏幕截图。 JConsole 屏幕截图中的尖峰来自运行 GC。

Docker Stats with memory usage

JConsole heap memory usage

MAT heap dump

最佳答案

JConsole 为您提供已提交的内存量:3311616 KiB ~= 3GiB 正如操作系统所见,这是您的 Java 进程消耗的内存量。

它与当前用于保存 Java 对象的堆大小无关,JConsole 也报告为 130237 kbyte ~= 130 MiB。

这也与实际存活的对象数量无关:默认情况下,当您加载堆转储时,MAT 将删除无法访问的对象。您可以通过转到 Preferences -> Memory Analyzer -> Keep Unreachable Objects 来启用该选项(参见 the MAT documentation)。因此,如果您有很多生命周期短的对象,则差异可能会非常大。

我看到它还报告了大约 9GiB 的最大堆。这意味着您已将 Xmx 参数设置为较大的值。

热点 GC 不太擅长回收未使用的内存。他们倾向于使用所有可用的空间(最大堆大小,由 Xmx 设置),然后从不取消提交堆,有效地将其保留给 Java 进程,而不是将其释放给操作系统。

如果你想从操作系统的角度最小化你的进程的内存占用,我建议你设置一个较低的Xmx,可能是-Xmx1g,这样就不会让Java增长太多(当然,Xmx也会需要足够高以适应您的应用程序工作负载!)。

如果真的想要自适应堆,您还可以切换到 G1 (-XX:+UseG1GC) 和更新的 Java,因为热点团队已交付 some improvements最近。

关于java - JConsole 堆转储比内存使用量小得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55795546/

相关文章:

java - 如何将图像字节传递给 Velocity 模板

java - 在JAVA中递归计算字符串中的字符

java - 如何在单击按钮显示新阶段时关闭当前阶段而不使新阶段的组件处于非 Activity 状态

linux - 将作业添加到 crontab

linux - Solaris -> Linux 迁移上的 Solaris 特定功能

java - 如何更改字符串资源 Xml 值?

java - CallObjectMethod/CallObjectMethodV : Ineligible receiver 中的 JNI 错误

部署在 STS 中的 Spring Boot 应用程序运行良好,但在 IntelliJ Idea 中则不行

java - 如何使用我的子模块中的 application.yml 文件?

spring-boot - 打包应用程序时未执行 Liquibase 脚本