java - 为什么运行 Java 应用程序的机器几乎没有物理内存,但仍运行数周

标签 java performance

我有一个部署在两台机器上的 Java 应用程序,根据指标(包括 JMC)判断,它们几乎都耗尽了内存,并且持续了相当长的时间。但是,应用程序运行正常,没有发生 OutOfMemory 错误。 enter image description here

这令人困惑。你能解释为什么应用程序仍然运行而没有 OutOfMemory 错误吗?为什么内存没有在接近极限时更早释放?

PS 这里是堆指标

enter image description here

最佳答案

这正是 Java 内存管理的工作原理 - 它基本上会延迟垃圾收集直到必要时,希望应用程序能够在需要 GC 之前退出。

因此它通常会选择从操作系统分配更多内存,直到达到 -Xmx 或操作系统/总 RAM 限制给出的限制,然后才会执行主要的垃圾收集器运行.这些运行将释放一些内存,然后应用程序将运行更多时间,直到再次遇到限制。

如果应用程序需要逐渐增加内存,那么在达到内存限制后会发生主要 GC 运行越来越频繁(随着需要的内存增加,而 GC 清除的内存减少)并且 GC 运行会变长。在某些时候,VM 可能会开始在 GC 中花费比运行应用程序更多的时间。

这样,Java 进程可能会运行很长时间(可能“永远”)并消耗几乎所有可用内存,而实际应用程序几乎没有实际运行时间,因为几乎所有 CPU 时间都在在GC度过。 Java 可能会检测到这种情况并抛出 java.lang.OutOfMemoryError 消息 GC Overhead Limit Exceeded,但并非总是如此。


如果你想诊断你的应用程序是否只是优化内存使用,或者实际上是内存不足,你需要找出 VM 在 GC 上花费了多少时间,以及趋势是什么。一些可能的方式:

  • 连接 JConsole 或 VisualVM(两者都是 JDK 的一部分)并检查 GC 运行(间隔和持续时间)
  • 如果您的 Java 应用程序是单线程的,则更简单的方法是观察 CPU 负载 - 默认 GC 是多线程的,因此在 GC 运行期间,它主要运行在更多的处理器/内核上,CPU 负载将超过 100单核的百分比(在 unix top 中为 >100%),而单线程应用程序仅导致单核的负载高达 100%。

关于java - 为什么运行 Java 应用程序的机器几乎没有物理内存,但仍运行数周,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51854919/

相关文章:

java - 如何将此 URL 与 java 正则表达式匹配

java - 将双向实体方法与 Mapstruct 结合使用

performance - 有效的数据结构来保存带有通配符的字符串

python - 在循环语句中访问python类成员容器效率低吗?

java - 对列表中的值求和。我可以更有效地做到这一点吗?

php - 使用 PHP 从文件中读取最后几行(即 "tail")的最佳方法是什么?

java - Spring security - 无法进入登录页面

java - “打开项目”遇到错误

java - 创建用户定义的地理围栏的算法

java - 在 LWJGL 中快速渲染 20 000 个矩形