为什么 Java 进程的 RES 内存持续缓慢增长,甚至对于开箱即用的 Spring Boot 管理也是如此?

问题描述 投票:0回答:3

我在一台 32GB 的机器上运行 23 个 Java 进程。没有进程指定 JVM 内存参数,例如 Xmx。

java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
报告最大默认堆大小如预期为 8GB。

每个进程都运行嵌入式 Tomcat(Spring Boot 应用程序(大多数版本为 2.3.4)),除了一个是运行三个 WAR 的独立 tomcat 9 实例。这些应用程序的使用率较低(通常是一名用户每天使用 10 分钟)。它们不是内存或 CPU 密集型的。其中之一是 Spring Boot admin,另一个是 Spring Cloud 的 Eureka 服务注册表。对于这两个,我只有一个主要方法来简单地引导 Spring Boot 应用程序。

然而,如顶部所示,每个进程的

RES
内存不断增加。例如,Spring Boot 服务注册表在过去 12 小时内从 1.1GB 增加到 1.5GB。所有进程都显示
RES
类似的小幅增加,但在同一 12 小时内,总增加使可用内存减少了 2 GB。过去 12 小时(依此类推)也是如此,直到当前可用内存仅为 4.7GB。

我担心的是,我继续看到这种趋势(即使没有使用应用程序)。内存永远不会从应用程序中释放,因此可用内存总量持续减少。这是正常的吗,因为也许每个 JVM 都会看到操作系统中的内存仍然可用并且有 8GB 堆空间可供使用?一旦达到操作系统可用内存阈值,JVM 是否会在某个时刻停止占用内存?还是会一直持续到所有可用内存都被用完为止?

更新

大多数应用程序使用的堆小于 200MB,但堆大小为 1.5 - 2.8GB。堆最大为 8GB。

java linux spring-boot memory jvm
3个回答
2
投票

操作系统报告的驻留内存不会告诉您哪个组件正在消耗它。您必须收集额外的数据才能确定流程的哪一部分正在增长

你必须追踪

  • java 堆和元空间的使用 - 您可以使用 JMC、gc 日志记录和许多其他 java 监控工具来监控此情况
  • jvm 堆外使用 - NMT
  • 直接字节缓冲区使用 - MX beans,也可通过 JMC 获得
  • 通过映射文件使用 -
    pmap -x <pid>
  • 由本机库使用,例如通过 JNI 使用 - 难以监控

0
投票

我也遇到过这种情况,经过长时间的研究,我找到了解决方案here。基本上,对于我的情况,这只是在 jar 调用上设置 xms 和 xmx 参数的问题,迫使 GC 不断地行动。


0
投票

这里接受的答案可能对您有帮助。

Java 进程的常驻内存使用量 (RSS) 不断增长

为 tomcat9 JVM 设置这些对我自己的情况有所帮助,即低使用率、低内存应用程序仍然会根据 Linux 上的 top 继续消耗 RSS。这些环境变量禁用一些用于释放内存的动态 Glibc 启发式方法,这在某些 Tomcat 场景中不会执行。

export MALLOC_ARENA_MAX=4
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536

当前 JVM 中的一个解决方法(至少对于 Java 11 向前版本)是使用

System.trim_native_heap
选项来
jcmd
:

sudo jcmd <pid> System.trim_native_heap

有一些关于 Glibc 不将内存返回给操作系统的问题的讨论,看起来您可能正在使用 Linux。

https://bugs.openjdk.org/browse/JDK-8269345

https://bugs.openjdk.org/browse/JDK-8293114

https://marc.info/?l=openjdk-serviceability-dev&m=168879617126137

© www.soinside.com 2019 - 2024. All rights reserved.