Java内存统计差异:jconsole、ps、prstat数值为何不同?
Solaris 10下Java 8进程内存统计差异解析
1. 操作系统工具与jconsole统计差异的原因
jconsole展示的Committed、Used、Max仅针对Java堆内存,而操作系统工具(ps/prstat/pmap)统计的是整个进程的全部内存开销,二者统计范围完全不同,差异主要来自以下几部分:
- Metaspace(元空间):Java 8替代PermGen的内存区域,存储类元数据、方法信息等,默认无上限(仅受系统内存限制),类加载较多时会占用大量内存,这部分不在堆统计范围内。
- 线程栈内存:每个Java线程默认分配1MB栈空间(可通过
-Xss调整),若进程内有数百个线程,累计内存会非常可观。 - JVM自身开销:包括JVM二进制执行文件、共享库(如
libjvm.so)、JIT编译后的代码缓存等,属于进程内存但不属于Java堆。 - 直接内存:通过
ByteBuffer.allocateDirect()分配的本地内存,不在堆统计中,常用于NIO场景。 - 本地代码内存:JNI调用或第三方本地库分配的内存,同样不属于Java堆范畴。
你的场景中,jconsole的Committed(61.9MB)只是堆的已提交内存,而操作系统统计的310MB虚拟内存、260MB物理内存是上述所有内存区域的总和,因此出现5倍左右的差异完全正常。
2. 哪项统计决定进程运行数量?
不存在绝对的“准确”统计,需根据关注的故障类型判断:
- 若关注Java堆
OutOfMemoryError:以jconsole的Max(119.5MB,对应-Xmx128m的实际可用值)为准。当进程堆内存使用接近该值时,会触发堆内存不足的OOM。按12GB系统内存计算,理论上最多可启动约96个进程(12288MB/128MB),但实际因其他内存开销,数量会低于此值。 - 若关注系统级内存耗尽(如触发Solaris的OOM Killer或无法启动新进程):以操作系统工具统计的RSS(260MB物理内存)为准。此时12GB内存最多可启动约47个进程(12288MB/260MB),接近你提到的40个(需预留系统自身及其他进程的内存开销)。
简单来说:
- 想避免Java堆OOM:参考jconsole的
Max值规划进程数 - 想避免系统内存不足:参考操作系统的RSS值规划进程数
内容的提问来源于stack exchange,提问作者William M. Donnelly
相关产品推荐
相关产品推荐

