【Do家】通过pmap命令解读jvm内存占用情况

1、执行Linux的pmap命令,采集到如下数据:
Linux代码  收藏代码
  1. # pmap -x 87|more  

87: /usr/local/java/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -server -Xms4G -Xmx4G -Xmn1G -Xss512k -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1024
Address           Kbytes     PSS   Dirty    Swap  Mode  Mapping
0000000000400000       4       1       0       0  r-xp  /usr/local/java/jre/bin/java
0000000000600000       4       4       4       0  r--p  /usr/local/java/jre/bin/java
0000000000601000       4       4       4       0  rw-p  /usr/local/java/jre/bin/java
0000000002271000    6392    6196    6196       0  rw-p  [heap]
00000006c0800000 4221440 3285332 3285332       0  rw-p    [ anon ]
00000007c2280000 1021440       0       0       0  ---p    [ anon ]
00007f6a0d22a000    1280     996     996       0  rw-p    [ anon ]
00007f6a0d36a000     768       0       0       0  ---p    [ anon ]
00007f6a0d42a000    2048    1980    1980       0  rw-p    [ anon ]
00007f6a0d62a000    2048    2044    2044       0  rw-p    [ anon ]
00007f6a0d82a000    2048    2040    2040       0  rw-p    [ anon ]
00007f6a0da2a000    2048    2044    2044       0  rw-p    [ anon ]
00007f6a0dc2a000      12       0       0       0  ---p    [ anon ]
00007f6a0dc2d000     504       8       8       0  rw-p    [ anon ]
00007f6a0dcab000      12       0       0       0  ---p    [ anon ]
00007f6a0dcae000     504      12      12       0  rw-p    [ anon ]
00007f6a0dd2c000      12       0       0       0  ---p    [ anon ]
00007f6a0dd2f000     504       8       8       0  rw-p    [ anon ]
00007f6a0ddad000      12       0       0       0  ---p    [ anon ]
00007f6a0ddb0000     504       8       8       0  rw-p    [ anon ]
00007f6a0de2e000      12       0       0       0  ---p    [ anon ]

2、通过os命令分析Java进程中包含线程数据
Linux代码  收藏代码
  1. # cat /proc/87/status |grep Threads  

Threads:        292
Linux代码  收藏代码
  1. # pmap -x 87 |awk -F' ' '{print $2}' |grep 504 |wc -l  

298

线程数量:292
3、通过status统计的Java进程实际物理内存占用,参见VmRSS参数
Linux代码  收藏代码
  1. # cat /proc/88/status |grep Vm  

VmPeak: 12399068 kB
VmSize: 12289588 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:   3105500 kB
VmRSS:   3103724 kB
VmData:  7152972 kB
VmStk:       244 kB
VmExe:         4 kB
VmLib:     18152 kB
VmPTE:      6700 kB
VmSwap:        0 kB

VmRSS=>3103724KB

4、通过pmap统计的Java进程实际占用物理内存,参见PSS参数
Linux代码  收藏代码
  1. # pmap -x 88 |grep total  

total            12289592 3098242 3078148

PSS=>3098242
5、解读如下:
1> JVM中heap占用空间,体现为:
00000006c0800000 4221440 3285332 3285332       0  rw-p    [ anon ]
主要关注PSS这列,由于heap采用了固定大小,-Xms4G -Xmx4G,os预留给Java进程的Heap大小为:4221440KB

2> JVM中CompressedClassSpaceSize,体现为:
00000007c2280000 1021440       0       0       0  ---p    [ anon ]
JVM默认的参数CompressedClassSpaceSize,压缩的类空间大小为1024KB

3> JVM中线程的栈占用的空间大小,512KB,即通过参数控制-Xss512k,体现为:
00007f6a0dc2d000     504       8       8       0  rw-p    [ anon ]
00007f6a0dcab000      12       0       0       0  ---p    [ anon ]
由于线程栈是每个线程独占的,占用空间取决于线程的数量,所以会出现重复的该数据段。

4> 其他的MetaSpace和本地内存使用,在pmap也有对应分配地址体现

【小结】
1> PSS实际上稍大于RSS,都是体现Java进程实际占用的物理内存大小;
2> 如果Java进程占用物理内存利用率高,与是否FGC无关;考虑线程数波动和本地内存的消耗,一般Heap都是固定大小的;
3> 从os角度,内存划分给Java进程后,即便是空间回收了,但是os也会预留该空间,认为此空间由进程使用中;
4> mapping为anon,即anonymous memory mappings,匿名内存映射,由os动态分配内存出去的空间;