23_JVM 统计检测工具
1783字约6分钟
2024-08-10
jstat
介绍
jstat
命令可以查看堆内存各部分的使用量,以及加载类的数量
命令的格式:jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
jstat -gc PID
jstat -gc PID 1000 10
命令表示秒统计 1
次,共统计 10
次
针对 Java
进程执行这个命令,就可以看这个 Java
进程(JVM
)的内存和 GC
情况了
列名 | 描述 |
---|---|
S0C | From Survivor 区大小 |
S1C | To Survivor 区大小 |
S0U | From Survivor 区当前使用内存大小 |
S1U | To Survivor 区当前使用内存大小 |
EC | Eden 区大小 |
EU | Eden 区当前使用内存大小 |
OC | 老年代大小 |
OU | 老年代当前使用大小 |
MC | 元数据区(方法区、永久代)大小 |
MU | 元数据区(方法区、永久代)当前使用内存大小 |
YGC | 系统运行到目前为止 Young GC 次数 |
YGCT | 系统运行到目前为止 Young GC 总耗时 |
FGC | 系统运行到目前为止 Full GC 次数 |
FGCT | 系统运行到目前为止 Full GC 总耗时 |
GCT | 系统运行到目前为止 GC 总耗时 |
其他 jstat 命令
jstat -gccapacity PID
:堆内存分析jstat -gcnew PID
:年轻代GC
分析,TT
和MTT
可以看到对象在年轻代存活的年龄以及存活的最大年龄jstat -gcnewcapacity PID
:年轻代内存分析jstat -gcold PID
:老年代GC
分析jstat -gcoldcapacity PID
:老年代内存分析jstat -gcmetacapacity PID
:元数据区内存分析
jstat 使用关注信息
分析线上 JVM
进程,我们主要关注下面这些信息
新生代对象增长速率
Young GC
触发频率Young GC
耗时Young GC
后存活对象以及有多少对象进入了老年代老年代对象增长速率
Full GC
触发频率Full GC
耗时
新生代对象增长速率
通过 jstat -gc PID 1000 10
命令,我们可以灵活的固定频率输出统计信息,观察每间隔一段时间 jvm
中 Eden
区对象占用变化
比如说执行这个命令后,第一秒显示 Eden
区使用了 100MB
内存,第二秒显示 Eden
区使用了 110MB
内存,第三秒显示 Eden
区使用了 118MB
内存,以此类推
我们可以推断出系统每秒钟大概新增 9MB
左右的对象
Young GC 触发频率和每次耗时
Young GC
多久触发一次我们可以根据新生代对象增长速率推测出来
比如 Eden
区有 500MB
内存,高峰期每秒新增 10MB
对象,那么高峰期就是 50
秒触发一次 Young GC
平时每秒新增 1MB
对象,那么大概需要 500
秒触发一次 Young GC
通过 jstat
命令查看,我们知道系统运行到目前为止 Young GC
发生总次数、总耗时,比如总共发生 100
次,总耗时 10
秒,那么平均每次 Young GC
就耗时 100
毫秒
也就知道每次 Young GC
时会导致系统停顿大概 100
毫秒
每次 Young GC 后有多少对象存活以及进入老年代
通过 jstat -gc PID 1000 10
命令,我们观察 Eden
、Survivor
、老年代的对象变化
一般来说,老年代对象不太可能不停的快速增长,系统没有那么多长期存活对象
如果每次 Young GC
过后,老年代对象都增长几十 MB
,那很有可能是一次 Young GC
过后存活对象太多了
存活对象太多,可能导致放入 Survivor
区之后触发动态年龄判断规则进入老年代,也有可能是 Survivor
区放不下,大部分存活对象进入老年代
jmap
如果只是了解 JVM
的运行状况去进行优化,通常来说 jstat
就够用了
有时候我们发现 JVM
新增对象速度很快,就想去看看到底什么对象占据了那么多的内存,就可以用 jmap
命令去看下 jvm
中的对象分布
jmap -heap PID
使用 jmap -heap PID
命令可以打印出来堆内存相关的一些参数设置以及当前堆内存各个区域的情况,比如 Eden
、Survivor
、老年代总容量、已使用容量、剩余容量
一般也不会用 jmpa
来看这些信息,毕竟信息还没 jstat
看得全,也没有 gc
相关统计数据
[root@eb6113 harts]# jmap -heap 93534
Attaching to process ID 93534, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.261-b12
using thread-local object allocation.
Parallel GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 536870912 (512.0MB)
NewSize = 134217728 (128.0MB)
MaxNewSize = 134217728 (128.0MB)
OldSize = 402653184 (384.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 113246208 (108.0MB)
used = 27318456 (26.05290985107422MB)
free = 85927752 (81.94709014892578MB)
24.123064676920574% used
From Space:
capacity = 8912896 (8.5MB)
used = 8736504 (8.331779479980469MB)
free = 176392 (0.16822052001953125MB)
98.02093505859375% used
To Space:
capacity = 11534336 (11.0MB)
used = 0 (0.0MB)
free = 11534336 (11.0MB)
0.0% used
PS Old Generation
capacity = 402653184 (384.0MB)
used = 33891448 (32.32140350341797MB)
free = 368761736 (351.67859649658203MB)
8.417032162348429% used
31911 interned Strings occupying 3194728 bytes.
jmap -histo PID
jmap -histo PID
命令会将各种对象占用内存空间的大小降序排列(占用内存最多的对象放最上面)
可以快速看到当前内存里哪个对象占用了大量内存空间
num #instances #bytes class name
----------------------------------------------
1: 353700 35541096 [C
2: 75913 6680344 java.lang.reflect.Method
3: 29370 5721104 [B
4: 223973 5375352 java.lang.String
5: 28495 4453696 [I
6: 68166 3592104 [Ljava.lang.Object;
7: 899 3449704 [J
8: 75009 2400288 java.util.concurrent.ConcurrentHashMap$Node
9: 62099 1987168 java.util.HashMap$Node
10: 16948 1883328 java.lang.Class
11: 21754 1862712 [Ljava.util.HashMap$Node;
12: 67143 1520680 [Ljava.lang.Class;
13: 33035 1321400 java.util.LinkedHashMap$Entry
14: 18847 966968 [Ljava.lang.String;
15: 869 945360 [Ljava.util.concurrent.ConcurrentHashMap$Node;
16: 19395 930960 java.util.HashMap
17: 15797 884632 java.util.LinkedHashMap
18: 10968 882840 [Ljava.util.WeakHashMap$Entry;
19: 11814 850608 java.lang.reflect.Field
20: 32338 776112 java.util.ArrayList
21: 8517 681360 java.lang.reflect.Constructor
... ..... ....... ...............
生成堆内存转储快照
如果觉得看到的对象占用内存情况不够,想要深入且仔细点的,可以用 jmap
命令生成一个堆内存快照放到一个文件里去,命令如下
jmap -dump:live,format=b,file=dump.hprof PID
执行命令后会在当前目录下生成一个 dump.hrpof
文件,由于是二进制格式没法直接打开看,后面通过 jhat
在浏览器中分析堆转储快照
jhat
使用 jhat
去分析堆快照,jaht
内置了 web
服务器,支持通过浏览器以图形化的方式分析堆转储快照
执行命令如下命令即可启动 jhat
服务器,默认 7000
端口号,也可以指定
jhat -port 7000 dump.hprof
执行命令后在浏览器访问这台机器的 7000
端口号,就可以通过图形化的方式去分析堆内存里对象分布情况了
其他 JVM 统计工具
系统上线后,需要对线上的 JVM
进行监控,一般来说有两种方法
第一种比较 low
,每天在高峰期和低峰期都用 jstat
、jmap
、jhat
等工具去线上系统看看 JVM
运行是否正常,有没有频繁 GC
问题
第二种就是使用一些其他工具,比如 Zabbix
、OpenFalcon
、Ganglia
,这些工具允许设置监控规则,比如多少分钟发生了多少次 Full GC
,就发送报警信息给你,不需要自己每天去看