最近排查一个 Java 服务的内存占用问题时,遇到了一个比较容易误判的情况。
JVM 的堆内存看起来并没有异常,甚至 GC 也能够正常工作,但 Windows 任务管理器里的进程内存却一直比较高。
后来查看进程信息:
WorkingSetMB : 8046
PrivateMB : 9337
VirtualMB : 15852
这时候如果只看 JVM Heap,很容易认为:
“堆没满,应该没问题。”
但实际上,Windows 任务管理器看到的进程内存,并不等于 Java Heap。
一个 Java 进程除了 -Xms/-Xmx 控制的 Heap 之外,还可能使用:
Metaspace
Code Cache
线程栈
Direct Memory
JNI / Native Memory
JVM 自身的 Native 开销
所以看到 Java 进程占用 8GB,并不能直接说明 -Xmx 就用了 8GB。
排查 JVM 内存问题时,最好把两个概念分开:
JVM Heap 使用情况 ≠ 操作系统看到的 Java 进程总内存。
这也是为什么有时候 GC 日志看起来正常,但任务管理器里的内存依然很高。