您的位置 首页 java

java 进程 内存过大-如何快速排查?

java 进程 内存过大-如何快速排查?

第一步:查看 JVM 内部内存视图(最准)

使用 jstat 命令查看 JVM 自己报告的内存使用情况(需要安装 JDK 或 JRE 工具包):
# 查看 GC 情况和堆内存使用 (每秒刷新一次)
jstat -gc <PID> 1000

 

按照MB 显示:

jstat -gc <PID> 1000 | awk 'NR>1 {for(i=1;i<=8;i++)  $ i=sprintf("%.1fM",  $ i/1024)} 1'

 

如果是容器

docker exec confluence jstat -gc 1 1000

重点关注:S0, S1, E, O, M 这几列。
结论:如果 O (老年代) + E (新生代) 的总和接近 6.4G,说明是 Java 代码里的对象占用了内存(可能是缓存数据多,或者是内存泄漏)。

100%显示:

jstat -gcutil 2574156 1000

只要O 老年代不到100%就可以。

 

第二步:检查堆外内存(NMT)

如果 JVM 堆内存显示只用了 2G,但系统显示用了 6.4G,那就是堆外内存问题。你可以使用 jcmd 检查(需在启动参数加 -XX:NativeMemoryTracking=summary,若未开启则跳过):

# 查看 JVM 各部分内存占用总和
jcmd <PID> VM.native_memory summary

重点关注:Internal (直接内存) 和 Class (元空间) 的大小。

第三步:检查线程数

线程过多也会吃内存。查看该进程创建了多少线程:
# 查看进程的线程数
ps -T -p <PID> | wc -l

正常:几十到几百个线程。
异常:如果超过 1000 个线程,说明线程池配置可能有问题,或者发生了线程泄漏。

 

案例:

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
 0.0   8192.0  0.0   6108.4 1851392.0 204800.0 1097728.0   119886.8  163584.0 161331.5 18240.0 16972.5    103    0.510   0      0.000    0.510

 

这是一份通过 jstat -gc 命令获取的 JVM 垃圾回收实时统计报告13。这份数据显示了一个健康且运行良好的 Java 应用程序状态。
为了帮你读懂这些数字背后的含义,我将关键指标拆解如下:

1. 内存区域解读(单位:KB)

  • Eden 区(新生代)
    • 容量 (EC): 约 1.8 GB (1851392.0 KB)
    • 使用 (EU): 约 200 MB (204800.0 KB)
    • 状态:使用率约 11%,空间充足,没有填满,说明对象分配速率正常,不需要频繁触发 Minor GC。
  • Survivor 区(幸存者)
    • S0: 容量 0.0 KB(当前未使用)。
    • S1: 容量 8 MB,使用了约 6 MB
    • 状态:S0C 为 0 通常表示 JVM 在某些 GC 策略下动态调整了 Survivor 空间,或者当前 S0 被标记为未分配。目前存活对象主要在 S1 中。
  • Old 区(老年代)
    • 容量 (OC): 约 1.05 GB (1097728.0 KB)
    • 使用 (OU): 约 117 MB (119886.8 KB)
    • 状态:使用率约 11%,非常健康。老年代空间充裕,距离触发 Full GC 还有很远的距离。
  • Metaspace(元空间)
    • 使用 (MU): 约 157 MB (161331.5 KB)
    • 状态:接近容量上限(MC 约 159 MB),如果应用还在动态加载类,可能需要关注是否会触发元空间扩容。

2. 垃圾回收(GC)行为

  • Young GC (YGC):
    • 次数103 次
    • 耗时 (YGCT)0.510 秒
    • 分析:平均每次 Young GC 仅耗时约 5 毫秒。虽然发生了 103 次回收,但总耗时很短,说明新生代回收效率很高,没有造成明显的应用停顿。
  • Full GC (FGC):
    • 次数0 次
    • 耗时 (FGCT)0.000 秒
    • 分析这是最好的状态。说明应用运行至今,老年代还没有满,不需要进行全局的、耗时的 Full GC。

3. 总结与建议

  • 结论:这是一个运行平稳的 Java 应用。
    • 内存充足:新生代和老年代都有大量空闲空间。
    • GC 高效:只有正常的新生代回收(Young GC),没有出现卡顿性的 Full GC。
    • 性能良好:GC 总耗时(GCT)仅 0.510 秒,对应用性能影响极小。
  • 无需操作:目前的 JVM 内存配置(堆大小)对于当前的业务负载是合适的,不需要调整参数。
小贴士如果你在监控时发现 FGC 数字开始增加,或者 OU (老年代使用) 持续飙升且不下降,那才需要警惕内存泄漏或堆内存不足的问题。目前来看,一切正常。
案例2:
(base) [root@wiki ai]# jstat -gcutil 2574156 1000
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
     -  51.15  69.44  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  69.44  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  72.22  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  72.22  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  75.00  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  80.56  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  80.56  69.37  98.61  93.03     77    0.403     0    0.000    0.403
     -  51.15  83.33  69.37  98.61  93.03     77    0.403     0    0.000    0.403
根据你提供的 jstat -gcutil 实时监控数据,这个 Java 进程(PID 2574156)目前的运行状态总体稳定,内存使用处于正常水平,暂未出现明显的内存泄漏或 GC 瓶颈
以下是对关键指标的详细解读:

1. 内存区域使用率分析

  • Eden 区
    • 状态正常
    • 分析E 列(Eden区)从 69.44% 上升到了 83.33%,这表明程序正在持续产生新的对象。数值没有瞬间冲到 100% 后归零(YGC 未增加),说明 Eden 区大小设置合理,对象分配速率在可控范围内。
  • Survivor 区
    • 状态正常
    • 分析S1 保持在 51.15%,S0 显示为 -(通常表示未使用或当前未启用)。这说明 Survivor 区有足够的空间容纳幸存对象,没有发生因 Survivor 区满而导致的对象过早晋升到老年代。
  • 老年代
    • 状态稳定
    • 分析O 列(老年代)始终保持在 69.37%,非常稳定。这说明虽然有对象进入老年代(可能是长期存活对象),但速率很慢,且没有出现持续飙升的情况(排除了短时间内发生内存泄漏的可能)。
  • 元数据空间
    • 状态高水位运行
    • 分析M 列(元数据)高达 98.61%。这通常是因为应用加载了大量的类(例如大型框架、插件化应用如 Confluence)。虽然目前没报错,但这是一个需要注意的点,如果类加载数量继续增加,可能会触发 Metaspace GC 或 OOM。

2. 垃圾回收统计分析

  • 年轻代 GC
    • 次数YGC 固定为 77 次(在你的监控时间段内没有增加),说明这段时间没有发生新的 Young GC。
    • 耗时YGCT 为 0.403 秒,平均每次耗时很短,对应用吞吐量影响极小。
  • Full GC
    • 次数FGC 为 0
    • 耗时FGCT 为 0.000。
    • 结论:这是最健康的指标。说明系统至今(或近期)没有发生过 Full GC,老年代回收压力为零。

3. 潜在风险提示

  1. Metaspace 占用过高
    • M 列达到 98.61%。虽然 JDK8+ 的 Metaspace 默认不限上限(受限于物理内存),但如果系统物理内存不足,可能会导致频繁的元数据 GC 甚至崩溃。
    • 建议:如果应用运行稳定,可以忽略此警告;如果担心内存溢出,可以在启动参数中显式设置 -XX:MaxMetaspaceSize
  2. Eden 区增长趋势
    • 虽然目前没有触发 GC,但 Eden 区在几分钟内从 69% 增长到 83%。如果这种速率持续,很快会触发 Young GC。如果 Young GC 频率突然变高(例如每秒几次),则需要考虑增大年轻代(-Xmn)。

总结

当前系统健康状况良好。老年代稳定且无 Full GC,说明没有内存泄漏。唯一的关注点是 Metaspace 使用率极高,建议关注系统日志是否有 Metaspace 相关的警告。

欢迎来撩 : 汇总all

白眉大叔

关于白眉大叔linux云计算: 白眉大叔

热门文章