这里对运行中的java虚拟机jvm(hotspot虚拟机,其上运行着java程序)监控及问题排查进行介绍。
jvm内存划分为几个不同的区域,如下:
java中内存是动态分配的,对用就有垃圾收集,采用的算法有标记-清除(mark-sweep)算法、复制(copying)算法、标记-整理(mark-compact)算法。垃圾收集针对的是java堆和方法区(程序计数器、虚拟机栈、本地方法栈为线程私有,随着线程生和灭)。常用垃圾收集器有:
监控的内容有:
查看jvm进程。
格式:jps [option]
option:
-l:显示运行类的完整包
-q:只显示进程号
-m:显示给main方法的参数
-v:显示给jvm的完整参数
示例:
输入:jps -l
输出:
17419 com.dragon.study.msa_register_center.MsaRegisterCenterApplication
查看虚拟机配置信息。
格式:jinfo vmid
查看堆内存使用情况,类加载的数量等。
格式:jstat [ -option vmid [ interval [s|ms] [count] ] ]
option:
-options:查看可用参数
-class:类加载统计
-compiler
-gc:查看堆内存各区域使用情况
-gccapacity
-gccause:堆内存各区域使用占比,以及最后一次和当前(当前可能没有)引发垃圾回收的诱因
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil:查看堆内存各区域使用占比
-printcompilation:编译情况
示例1,查看堆内存各区域使用情况:
输入: jstat -gc 17419
输出:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
22528.0 20480.0 0.0 20287.0 794624.0 386301.9 96768.0 39076.0 73304.0 70454.7 9600.0 9037.9 11 1.539 3 0.320 1.859
解释:
容量的单位是KB
S0C: service0区容量
S1C: service1区容量
S0C: service0区使用量
S1C: service1区使用量
EC: eden区容量
EU: eden区使用量
OC: 老年代容量
OU: 老年代使用量
PC: 永久代容量
PUMU: 永乐代使用量
MC: 方法区容量
MU: 方法区使用量
CCSC: 压缩类空间容量
CCSU: 压缩类空间使用量
YGC: minor gc的次数
YGCT: minor gc耗时,单位秒
FGC: full gc的次数
FGCT: full gc耗时,单位秒
GCT: 所有gc耗时,单位秒
示例2,查看堆内存各区域使用占比:
输入: jstat -gcutil 17419
输出:
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 99.06 48.83 40.38 96.11 94.15 11 1.539 3 0.320 1.859
解释:
S0: service0使用比例
S1: service1使用比例
EC: eden区使用比例
O: 老年代使用比例
M: 方法区使用比例
CCS: 压缩类空间使用量
YGC: minor gc的次数
YGCT: minor gc耗时,单位秒
FGC: full gc的次数
FGCT: full gc耗时,单位秒
GCT: 所有gc耗时,单位秒
示例3,类加载统计:
输入: jstat -class 17419
输出:
Loaded Bytes Unloaded Bytes Time
13604 27320.2 1 1.1 39.70
示例4,堆内存各区域使用占比,以及最后一次和当前(当前可能没有)引发垃圾回收的诱因:
输入: jstat -gccause 17419
输出:
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 99.06 51.05 40.38 96.11 94.15 11 1.539 3 0.320 1.859 Allocation Failure No GC
生成堆转储快照,查看堆详细信息等。
格式:jmap [option] vmid
option:
-heap: 显示堆详细信息,使用的哪种回收器、分代使用情况
-histo: 显示堆中对象统计信息
-finalizerinfo: 在F-Queue中等待Finalizer线程执行finalize方法的对象
-dump: 生成堆转储快照(配合jhat使用),格式为: -dump:[live,]format=b,file= live子参数指明是否只出存活的参数
示例1,显示堆详细信息,使用的哪种回收器、分代使用情况:
输入: jmap -heap 17419
输出:
Attaching to process ID 17419, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2573205504 (2454.0MB)
NewSize = 53477376 (51.0MB)
MaxNewSize = 857735168 (818.0MB)
OldSize = 108003328 (103.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 = 813694976 (776.0MB)
used = 417139520 (397.81524658203125MB)
free = 396555456 (378.18475341796875MB)
51.26485136366382% used
From Space:
capacity = 20971520 (20.0MB)
used = 20773896 (19.81153106689453MB)
free = 197624 (0.18846893310546875MB)
99.05765533447266% used
To Space:
capacity = 23068672 (22.0MB)
used = 0 (0.0MB)
free = 23068672 (22.0MB)
0.0% used
PS Old Generation
capacity = 99090432 (94.5MB)
used = 40013792 (38.160125732421875MB)
free = 59076640 (56.339874267578125MB)
40.38108543113426% used
44501 interned Strings occupying 5591688 bytes.
示例2,生成堆转储快照:
输入: jmap -dump:format=b,file=17419.txt 17419
结果:新生成文件17419.txt文件,解析配合jhat使用
jvm转储快照分析工具。
格式:jhat filename
示例,使用前面生成的dump文件17419.txt:
jhat 17419.txt
运行后在浏览器中使用地址: http://localhost:7000 查看
查看当前时刻每一个线程正在执行的方法堆栈信息。
格式:jstack [option] vmid
option:
-F: 当正常输出请求不被相应时,强制输出
-l: 除堆栈外,还输出锁信息
示例:
输入: jstack -l 17419
部分输出:
"http-nio-8010-ClientPoller-1" #114 daemon prio=5 os_prio=0 tid=0x00007f421354a800 nid=0x44e9 runnable [0x00007f41409d4000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000007a137e200> (a sun.nio.ch.Util$3)
- locked <0x00000007a137e1f0> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000007a137e0d8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:754)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
解析:
nid为16进制的线程id。
这里以排查应用程序cpu使用率过高为例,排查步骤如下:
输入: top
输出:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20959 china 20 0 8345840 635048 25048 S 4.6 6.3 0:24.87 java
由上输出确定,占cpu过高pid为20959
输入: top -Hp 20959
部分输出:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20960 china 20 0 8345840 636332 25048 S 0.7 6.3 0:17.92 java
21060 china 20 0 8345840 636332 25048 S 0.3 6.3 0:01.55 java
由上输出确定,占cpu过高线程id为20960
输入: printf '%x\n' 20960
输出:51e0
20960的16进制为51e0
输入: jstack 20959 | grep -i -A10 51e0
输出:
"main" #1 prio=5 os_prio=0 tid=0x00007f7040018800 nid=0x51e0 waiting on condition [0x00007f7049190000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.dragon.study.msa_client.MsaClientApplication.main(MsaClientApplication.java:26)
由此可发现MsaClientApplication类的26行可能有问题。
现象:
Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process: ptrace(PTRACE_ATTACH, ..) failed for 19948: Operation not permitted
解决:
方式一(临时修改):
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
方式二(永久修改):
vim /etc/sysctl.d/10-ptrace.conf
将 kernel.yama.ptrace_scope = 1 改为: kernel.yama.ptrace_scope =0