最近排查一个 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 日志看起来正常,但任务管理器里的内存依然很高。