jvm问题排查工具

jdk自带的jvm监控工具

Java自带了几个jvm监控工具,如jstat、jmap、jstack。

jstat

jstat是常见的线上jvm问题排查工具,jstat用法:

说明:

  • lines: 使用interval参数,会在间隔指定时间后输出当前JVM内存的状态,这个参数是指定输出多少行后,再输出title,这样就不需要翻屏看这一列的title了。
  • vmid: 虚拟机的pid
  • interval:间隔多少时间后循环输出,不指定的话,就输出一次
  • count:指定输出多少次

jstat -option选项

]# jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation

jstat -gc

间隔1s统计输出一次,共统计10次。

含义详解:

参数描述
S0C年轻代中第一个survivor(幸存区)的容量 (字节)
S1C年轻代中第二个survivor(幸存区)的容量 (字节)
S0U年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC年轻代中Eden(伊甸园)的容量 (字节)
EU年轻代中Eden(伊甸园)目前已使用空间 (字节)
OCOld代的容量 (字节)
OUOld代目前已使用空间 (字节)
PCPerm(持久代)的容量 (字节)
PUPerm(持久代)目前已使用空间 (字节)
YGC从应用程序启动到采样时年轻代中gc次数
YGCT从应用程序启动到采样时年轻代中gc所用时间(s)
FGC从应用程序启动到采样时old代(全gc)gc次数
FGCT从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT从应用程序启动到采样时gc用的总时间(s)

jstat -gcutil 

每隔lines显示title: jstat -gcutil -h<lines> pid  interval

详细含义:

参数描述
S0年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E年轻代中Eden(伊甸园)已使用的占当前容量百分比
Oold代已使用的占当前容量百分比
Pperm代已使用的占当前容量百分比
YGC从应用程序启动到采样时年轻代中gc次数
YGCT从应用程序启动到采样时年轻代中gc所用时间(s)
FGC从应用程序启动到采样时old代(全gc)gc次数
FGCT从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT从应用程序启动到采样时gc用的总时间(s)

jstat -gccapacity

 

参数描述
NGCMN年轻代(young)中初始化(最小)的大小 (字节)
NGCMX年轻代(young)的最大容量 (字节)
NGC年轻代(young)中当前的容量 (字节)
S0C年轻代中第一个survivor(幸存区)的容量 (字节)
S1C年轻代中第二个survivor(幸存区)的容量 (字节)
EC年轻代中Eden(伊甸园)的容量 (字节)
OGCMNold代中初始化(最小)的大小 (字节)
OGCMXold代的最大容量 (字节)
OGCold代当前新生成的容量 (字节)
OCOld代的容量 (字节)
PGCMNperm代中初始化(最小)的大小 (字节)
PGCMXperm代的最大容量 (字节)
PGCperm代当前新生成的容量 (字节)
PCPerm(持久代)的容量 (字节)
YGC从应用程序启动到采样时年轻代中gc次数
FGC从应用程序启动到采样时old代(全gc)gc次数

 

jmap

用法:

说明:

 

 -F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 

 -h | -help 打印辅助信息 

 -J 传递参数给jmap启动的jvm. 

 

jmap -heap pid

打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.

Concurrent Mark-Sweep GC 

using parallel threads in the new generation.  //新生代采用的是并行线程处理方式
using thread-local object allocation.   
Concurrent Mark-Sweep GC   //同步并行垃圾回收

Heap Configuration:  //堆配置情况
   MinHeapFreeRatio = 40 //最小堆使用比例
   MaxHeapFreeRatio = 70 //最大堆可用比例
   MaxHeapSize      = 2147483648 (2048.0MB) //最大堆空间大小
   NewSize          = 268435456 (256.0MB) //新生代分配大小
   MaxNewSize       = 268435456 (256.0MB) //最大可新生代分配大小
   OldSize          = 5439488 (5.1875MB) //老生代大小
   NewRatio         = 2  //新生代比例
   SurvivorRatio    = 8 //新生代与suvivor的比例
   PermSize         = 134217728 (128.0MB) //perm区大小
   MaxPermSize      = 134217728 (128.0MB) //最大可分配perm区大小

Heap Usage: //堆使用情况
New Generation (Eden + 1 Survivor Space):  //新生代(伊甸区 + survior空间)
   capacity = 241631232 (230.4375MB)  //伊甸区容量
   used     = 77776272 (74.17323303222656MB) //已经使用大小
   free     = 163854960 (156.26426696777344MB) //剩余容量
   32.188004570534986% used //使用比例
Eden Space:  //伊甸区
   capacity = 214827008 (204.875MB) //伊甸区容量
   used     = 74442288 (70.99369812011719MB) //伊甸区使用
   free     = 140384720 (133.8813018798828MB) //伊甸区当前剩余容量
   34.65220164496263% used //伊甸区使用情况
From Space: //survior1区
   capacity = 26804224 (25.5625MB) //survior1区容量
   used     = 3333984 (3.179534912109375MB) //surviror1区已使用情况
   free     = 23470240 (22.382965087890625MB) //surviror1区剩余容量
   12.43827838477995% used //survior1区使用比例
To Space: //survior2 区
   capacity = 26804224 (25.5625MB) //survior2区容量
   used     = 0 (0.0MB) //survior2区已使用情况
   free     = 26804224 (25.5625MB) //survior2区剩余容量
   0.0% used // survior2区使用比例
concurrent mark-sweep generation: //老生代使用情况
   capacity = 1879048192 (1792.0MB) //老生代容量
   used     = 30847928 (29.41887664794922MB) //老生代已使用容量
   free     = 1848200264 (1762.5811233520508MB) //老生代剩余容量
   1.6416783843721663% used //老生代使用比例
Perm Generation: //perm区使用情况
   capacity = 134217728 (128.0MB) //perm区容量
   used     = 47303016 (45.111671447753906MB) //perm区已使用容量
   free     = 86914712 (82.8883285522461MB) //perm区剩余容量
   35.24349331855774% used //perm区使用比例

Parallel GC

using thread-local object allocation.
Parallel GC with 4 thread(s)          //GC 方式          

Heap Configuration:       //堆内存初始化配置
MinHeapFreeRatio=40     //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio=70  //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize=512.0MB  //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize  = 1.0MB          //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
MaxNewSize =4095MB   //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
OldSize  = 4.0MB            //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
NewRatio  = 8         //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
SurvivorRatio = 8    //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值 
PermSize= 16.0MB       //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
MaxPermSize=64.0MB  //对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小

Heap Usage:               //堆内存分步
PS Young Generation
Eden Space:          //Eden区内存分布
capacity = 20381696 (19.4375MB)  //Eden区总容量
used     = 20370032 (19.426376342773438MB)  //Eden区已使用
free     = 11664 (0.0111236572265625MB)  //Eden区剩余容量
99.94277218147106% used  //Eden区使用比率
From Space:        //其中一个Survivor区的内存分布
capacity = 8519680 (8.125MB)
used     = 32768 (0.03125MB)
free     = 8486912 (8.09375MB)
0.38461538461538464% used
To Space:            //另一个Survivor区的内存分布
capacity = 9306112 (8.875MB)
used     = 0 (0.0MB)
free     = 9306112 (8.875MB)
0.0% used
PS Old Generation  //当前的Old区内存分布
capacity = 366280704 (349.3125MB)
used     = 322179848 (307.25464630126953MB)
free     = 44100856 (42.05785369873047MB)
87.95982001825573% used
PS Perm Generation  //当前的 “永生代” 内存分布
capacity = 32243712 (30.75MB)
used     = 28918584 (27.57891082763672MB)
free     = 3325128 (3.1710891723632812MB)
89.68751488662348% used

生成jvm dump快照

jmap -dump:format=b,file=/home/work/jinze/dump_26041_05231438.hprof ${pid} --> 生成二进制堆栈文件。
jmap -heap ${pid} --查看jvm堆栈内存占用情况
jmap -histo:live ${pid} | head -20  --查看jvm内存占用前20存活对象

jmap–histo

-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量。

]$ jmap -histo:live 14645 | head -10

 num     #instances         #bytes  class name
----------------------------------------------
   1:        901564     1777759440  [B
   2:        112206      123401632  [J
   3:       1462437       92280272  [C
   4:       2182305       69833760  java.util.concurrent.atomic.LongAdder
   5:        622976       68936400  [Ljava.lang.Object;
   6:       1518179       48581728  java.util.HashMap$Node
   7:        936736       44963328  java.util.HashMap
   8:        960914       38436560  java.util.TreeMap$Entry
   9:       1453265       34878360  java.lang.String
  10:       1380194       33124656  org.elasticsearch.common.util.concurrent.ReleasableLock

jmap -permstat pid

-permstat 打印classload和jvm heap永久区的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. jdk1.8后已移除。

jstack

jstack是jdk中自带的用于查看进程内线程栈的工具,很轻量易用,并且执行时不会对性能造成很大的影响。当程序出现死锁时,我们可以通过jstack打印线程栈找到问题。

jstack用法:

使用jstack定位问题

找出CPU消耗多的代码

如果程序cpu占用很高,我们需要找到问题并优化,可以配合top命令,找出最耗cpu的进程,从而找到相应代码解决问题。

1、先用jps找出程序pid,这里是23034

2、用top命令找出该进程最耗cpu的线程。

~]# top -Hp 23034

结果如下图

23046线程占了93.8的cpu,就是它。

 

3、将23046转成16进制。因为top里的pid是10进制,而jstack里是16进制,叫nid。

可以用printf命令转换

~]# printf "%x\n" 23046

得到 5a06

4、jstack出场

~]# jstack 23034 | grep 5a06

结果如下:

writeFileThread占用了最多的cpu资源。找到后,可以优化代码了。

使用jstack时,可能遇到下面的情况:

Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

原因:
1、jstack报错:Unable to open socket file。是因为这个java进程的pid文件删除了。
2、从Java 6 update 21 引入的bug sunbug 7009828,在Java 6 update 25修复。

解决办法:
1 修改tmpwatch设置

排查对应的/tmp/hsperfdata_*的目录,让jvm自己来管理,保证jps,jstat等命令可用。
修改/etc/cron.daily/tmpwatch
/usr/sbin/tmpwatch "$flags" -x /tmp/hsperfdata_* -x /tmp/.X11-unix -x /tmp/.XIM-unix
-x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp
2 java程序重启
3 由于jdk版本导致的问题,需要升级jdk版本

Thread Dump收集

jstack -l  <pid> > <file-path>

For Example:

jstack -l 37320 > /opt/tmp/threadDump.txt

 

堆分析工具

Memory Analyzer(MAT)

是一款Java堆分析工具,能够快速找到占用堆内存空间最多的对象,以便程序进行优化,减少内存消耗,定位可能的内存泄漏问题。

对于生产环境,dump出来的文件可能会超过16GB,自己的台式机或者笔记本的内存根本不够用。可以下载linux系统的MAT,然后在linux上进行分析。

配置mat的-Xmx大小

  • 解压MemoryAnalyzer-*.x86_64.zip,然后修改mat的配置文件

打开MemoryAnalyzer.ini文件,修改-Xmx的值,取值根据hprof文件的大小

-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.700.v20180518-1200
-vmargs
-Xms40960m
-Xmx40960m

执行分析命令

./ParseHeapDump.sh ../today_heap_dump/jvm.hprof org.eclipse.mat.api:suspects

支持另外两种分析结果:

org.eclipse.mat.api:overview
org.eclipse.mat.api:top_components 

后台分析,并记录执行日志

nohup ~/analysis/mat/ParseHeapDump.sh ./java_pid33461.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components & echo $! > pid

查看分析报告

在拿到结果后,只需要吧三个.zip包传到本地,解压后,用浏览器打开网页即可。

 

应用程序分析

Visual VM的Profiler

可以查看到程序对CPU和内存的使用情况,如分析程序中执行次数最多最耗时的方法,占用内存空间最多的对象等等。

程序动态跟踪工具 BTrace

BTrace是一个开源的Java程序动态跟踪工具。它通过Hotspot虚拟机的HotSwap技术将跟踪的代码动态替换到被跟踪的Java程序内,以观察程序运行的细节。

这个功能在实际的生产环境中十分有意义,每当在线运行的系统出现问题时,通过使用BTrace,可以在不修改代码、不重启应用的情况下,动态的查看程序运行的细节,方便的对程序进行调试。

 

参考:

how-to-take-thread-dumps-7-options;

jstat用法

Java jstack用法

https://blog.csdn.net/zhaozheng7758/article/details/8623530;

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值