JVM 使用内存分析

要全面查看一个 Java 应用的实际内存占用,需要从 JVM 内存区域系统进程内存堆外内存 三个维度综合分析。以下是详细方法和工具指南:

JVM 内存分析

1. 使用 jcmd + Native Memory Tracking (NMT)

# 启动应用时开启NMT监控
java -XX:NativeMemoryTracking=detail -XX:+UnlockDiagnosticVMOptions -jar your-app.jar

# 查看详细内存分布(运行后执行)
jcmd <PID> VM.native_memory detail

输出示例

Native Memory Tracking:
Total: reserved=12GB, committed=10GB
- Java Heap: reserved=8GB, committed=7GB        # -Xmx控制的堆内存
- Class: reserved=2GB, committed=1.5GB          # 类元数据(Metaspace)
- Thread: reserved=0.5GB, committed=0.3GB       # 线程栈(线程数 × -Xss)
- Code: reserved=1GB, committed=0.8GB           # JIT编译代码缓存
- GC: reserved=1.5GB, committed=1GB            # 垃圾回收器占用
- Internal: reserved=0.5GB, committed=0.3GB     # 直接内存(Direct Buffer)等
- Other: reserved=0.2GB, committed=0.1GB        # 其他JVM内部开销

📌 reserved vs committed 解析

reserved:JVM 向操作系统预先保留的虚拟内存总量(堆+非堆),但尚未全部占用物理内存。

committed:JVM 实际向操作系统申请并使用的物理内存(堆+非堆),这部分是真实开销。
实际测试

2. 使用 jstat 监控堆内存分区

jstat -gc <PID> 1s 5  # 每1秒采样1次,共5次

关键列

  • S0C/S1C:Survivor区容量
  • EU/OU:Eden/老年代使用量
  • MC/MU:Metaspace容量/使用量
  • CCSC/CCSU:压缩类空间

系统级内存分析

1. 查看进程物理内存(RES)

top -p <PID>  # 关注RES列
或
ps -p <PID> -o rss,vsz  # RSS=物理内存, VSZ=虚拟内存

2. 使用 pmap 分析内存映射

pmap -x <PID> | sort -n -k3  # 按内存占用排序

输出重点

  • [anon]:堆和堆外内存
  • [stack]:线程栈
  • 共享库(如libjvm.so

3. 检查共享内存(SHR)

smem -P java  # 显示USS/PSS/RSS(需安装smem)
  • USS:进程独占内存(最真实占用)
  • PSS:共享内存按比例分配后的值

堆外内存专项检查

1. 直接内存(Direct Buffer)

jcmd <PID> VM.native_memory summary | grep "Internal"
或
jmap -histo:live <PID> | grep "DirectByteBuffer"

2. JNI/Native 库内存

valgrind --tool=massif --pages-as-heap=yes java -jar app.jar  # 深度分析(Linux)

3. 内存映射文件(MMAP)

pmap <PID> | grep "mmap"
posted @ 2025-06-24 14:12  deyang  阅读(346)  评论(0)    收藏  举报