正文
引言
前面几章内容我们学习了JVM的内存回收和JVM参数等系列,今天墨白给大家分享的是jmap的使用以及内存溢出分析等详情,话不多说,正文开始;
昨天我们通过jstat可以对JVM堆的内存进行统计分析,而jmap可以获取到更加详细的内容,如:内存使用情况的汇总、对内存溢出的定位与分析。
在写这篇文章的时候我发现了一个问题,新版的Linux系统加入了 ptrace-scope 机制. 这种机制为了防止用户访问当前正在运行的进程的内存和状态, 而一些调试软件本身就是利用 ptrace 来进行获取某进程的内存状态的(包括GDB),所以在新版本的Linux系统, 默认情况下不允许再访问了,所以我们无法使用之前的jmap -heap这个命令了,今天我们用-clstats这个命令来查看JVM内存分析;
先查看下jmap的命令:
Example: jmap -dump:live,format=b,file=heap.bin
[root@localhost ~]# jmap -h
Usage:
== 连接到运行进程并打印类加载器统计信息
jmap -clstats
to connect to running process and print class loader statistics
== 连接到正在运行的进程并打印有关等待完成的对象的信息
jmap -finalizerinfo
to connect to running process and print information on objects awaiting finalization
== 连接到运行进程并打印Java对象堆的直方图
jmap -histo[:live]
to connect to running process and print histogram of java object heap
if the "live" suboption is specified, only count live objects
== 连接到正在运行的进程并转储Java堆
jmap -dump:
to connect to running process and dump java heap
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file= dump heap to
Example: jmap -dump:live,format=b,file=heap.bin
== 连接到运行进程并打印类加载器统计信息
[root@localhost bin]# jmap -clstats 30685
==================================省略3600条信息=================================
0 536 56 3584 9 449 2304 2024 4768 6792 websocket.snake.SnakeAnnotation
13578248 2340680 15712 7693904 40079 1987618 11822808 7659360 15423064 23082424 Total
58.8% 10.1% 0.1% 33.3% - 8.6% 51.2% 33.2% 66.8% 100.0%
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
细心找找我们发现它有几个关键字,如下
查看内存中对象数量及大小,如下:
1== 查看所有对象,包括活跃以及非活跃的
2[root@localhost ~]# jmap -histo 30685 | more
3 num #instances #bytes class name (module)
4-------------------------------------------------------
5 1: 60386 5335640 [B (java.base@9.0.4)
6 2: 1220 3146456 [C (java.base@9.0.4)
7 3: 42784 1026816 java.lang.String (java.base@9.0.4)
8 4: 19972 639104 java.util.HashMap$Node (java.base@9.0.4)
9 5: 5436 627008 [I (java.base@9.0.4)
10 6: 3824 462160 java.lang.Class (java.base@9.0.4)
11===============================忽略内容=======================================
12 41: 632 25280 java.util.LinkedHashMap$Entry (java.base@9.0.4)
对象说明:
== 对象说明
B byte
C char
D double
F float
I int
J long
Z boolean
[ 数组,如[I表示int[]
[L+类名 其他对象
有些时候我们需要将jvm当前内存中的情况dump到文件中,然后对它进行分析,jmap也是支持dump到文件中的,如下。
== 将内存使用的详细情况输出到文件
[root@localhost test]# jmap -dump:format=b,file=m.dat 30685
Heap dump file created
[root@localhost test]# ll
总用量 31752
drwxr-xr-x. 2 root root 6 10月 11 00:25 aaa
== 可以看到新建了一个m.dat的文件
-rw-------. 1 root root 32505476 10月 11 00:30 m.dat
-rw-r--r--. 1 root root 575 10月 8 23:58 TestJVM.class
-rw-r--r--. 1 root root 225 10月 8 23:58 TestJVM.java
我们将jvm的内存dump到文件中,这个文件是一个二进制的文件,不方便查看,这时我们可以借助于jhat工具进行查看。需要注意一点的是,Java9版本之后就没有jhat命令了;
== 通过jhat对dump文件进行分析
[root@node01 test]# jhat ‐port 9999 m.dat
Reading from /test/m.dat...
Dump file created Mon Sep 10 01:04:21 CST 2018
Snapshot read, resolving...
Resolving 204094 objects...
Chasing references, expect 40
dots........................................
Eliminating duplicate references........................................
Snapshot resolved.
Started HTTP server on port 9999
Server is ready.
打开浏览器进行访问:
打开浏览器进行访问:http://访问IP:9999/
这里面的内容就是jhat做的解析内容,可以看到它打包方式有一些是数组,如数组的对象有那些内容,还可以看到打包是以Javax.el方式又有一些,还有servlet等方式,它会以一些包的方式自动给我们分类,这些方法也可以点击进去查看详情.包括实例等等有很多内容,这里就不一一说了,感兴趣的小伙伴可以看一下,最后面还给我们提供了OQL查询功能;
这个功能类似SQL语句,下面我们看下是怎么使用的,它有给我们提供API,点击QQL Help就可以查看它的使用文档了;
现在我们自己来玩一下这个功能,查询一个字符串大于100的内容有哪些;