java程序内存分析
背景:近期有个java程序,起了12个实例,每个pod内存占用都在6G以上很高;
k8s exec 进入Pod查看内存分布:
root@stack-charge-server-0-0:/app# jcmd 1 VM.native_memory summary scale=MB
1:
Native Memory Tracking:
Total: reserved=8037MB, committed=6156MB
- Java Heap (reserved=5736MB, committed=5363MB)
(mmap: reserved=5736MB, committed=5363MB)
- Class (reserved=1173MB, committed=170MB)
(classes #26845)
( instance classes #25618, array classes #1227)
(malloc=9MB #136300)
(mmap: reserved=1164MB, committed=160MB)
( Metadata: )
( reserved=140MB, committed=138MB)
( used=131MB)
( free=7MB)
( waste=0MB =0.00%)
( Class space:)
( reserved=1024MB, committed=22MB)
( used=15MB)
( free=6MB)
( waste=0MB =0.00%)
- Thread (reserved=408MB, committed=51MB)
(thread #405)
(stack: reserved=407MB, committed=50MB)
(malloc=1MB #2432)
- Code (reserved=252MB, committed=119MB)
(malloc=11MB #34011)
(mmap: reserved=242MB, committed=108MB)
- GC (reserved=279MB, committed=265MB)
(malloc=33MB #115426)
(mmap: reserved=246MB, committed=232MB)
- Compiler (reserved=4MB, committed=4MB)
(malloc=4MB #3472)
- Internal (reserved=24MB, committed=24MB)
(malloc=24MB #12382)
- Other (reserved=84MB, committed=84MB)
(malloc=84MB #465)
- Symbol (reserved=25MB, committed=25MB)
(malloc=23MB #333931)
(arena=2MB #1)
- Native Memory Tracking (reserved=11MB, committed=11MB)
(malloc=1MB #9250)
(tracking overhead=10MB)
- Shared class space (reserved=11MB, committed=11MB)
(mmap: reserved=11MB, committed=11MB)
- Arena Chunk (reserved=21MB, committed=21MB)
(malloc=21MB)
- Module (reserved=5MB, committed=5MB)
(malloc=5MB #19147)
- Synchronizer (reserved=1MB, committed=1MB)
(malloc=1MB #10021)
root@stack-charge-server-0-0:/app# jcmd 1 GC.heap_info
1:
garbage-first heap total 5491712K, used 2032772K [0x0000000699800000, 0x0000000800000000)
region size 1024K, 1471 young (1506304K), 2 survivors (2048K)
Metaspace used 150172K, capacity 161395K, committed 164200K, reserved 1191936K
class space used 15850K, capacity 19820K, committed 22400K, reserved 1048576K
关键点:Java 堆 committed 5363 MB,但 used 仅 1985 MB,堆内存有 3.3G 以上是已申请但未使用的空闲空间。 非堆部分合计约 793 MB,占比不大。
GC.heap_info 进一步观察堆内存分析:
-
total 5491712K ≈ 5.24G:这是当前堆的总容量(committed),接近 NMT 的 5363MB。
-
used 2032772K ≈ 1.94G:实际存活对象+临时对象。
-
年轻代占用 1471 个 region ≈ 1.47G,survivor 2 个 region ≈ 2M。
-
推算老年代使用量 = 2032772K - 1506304K - 2048K ≈ 524420K ≈ 512M。
如何确定合适的堆大小?
目标:让 -Xmx 接近 Live Set(常驻内存的部分,FGC无法回收的) 的 2~3 倍,同时不超过容器内存的 70%。
jcmd 1 GC.run
jcmd 1 GC.heap_info
触发一次Full GC 后,total 522240K ≈ 510 MB, used 401136K ≈ 392 MB(=Live Set ),说明存在大量临时对象;
优化措施:
-
堆
-Xmx设为 1G~1.5G(Live Set 的 2.5~3.8 倍,足够容纳年轻代和晋升) -
-Xms=-Xmx,避免堆伸缩 -
保留元空间上限
-XX:MaxMetaspaceSize=256m -
直接内存按需
-XX:MaxDirectMemorySize=512m
调整后预期:
-
堆 committed ≈ 1.5G
-
非堆 ≈ 0.8G
-
Pod 总内存 ≈ 2.3G~2.5G,比现在降低 3.5G 以上;

浙公网安备 33010602011771号