JVM系列(2) JVM监控工具

0.可选GC配置

0.1 4C4G, 响应时优先的GC配置策略

-XX:+HeapDumpBeforeFullGC
-XX:+HeapDumpAfterFullGC
-XX:CMSFullGCsBeforeCompaction=3
-XX:CMSInitiatingOccupancyFraction=68
-XX:+CMSParallelRemarkEnabled
-XX:CompressedClassSpaceSize=850395136
-XX:+DisableExplicitGC
-XX:GCLogFileSize=1073741824
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/zy/heapdump
-XX:InitialHeapSize=67108864
-XX:+ManagementServer
-XX:MaxHeapSize=2576351232
-XX:MaxMetaspaceSize=858783744
-XX:MaxNewSize=348966912
-XX:MaxTenuringThreshold=6
-XX:NumberOfGCLogFiles=10
-XX:OldPLABSize=16
-XX:OnOutOfMemoryError=/opt/zy/thread_dump.txt
-XX:+PrintGC
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps
-XX:+PrintGCDetatils
-XX:+PrintGCTimeStamps
-XX:+UseCMSCompactAtFullCollection
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-Xloggc:/opt/zy/hello_gc_%t.log

0.2 吞吐量优先的GC配置可参见kafka的GC策略

1.JVM调优工具

// JVM 问题分析原则1
对于线上dump的heap信息,应该尽量拉去到线下用于可视化工具来分析,这样分析更详细。
如果对于一些紧急的问题,必须需要通过线上监控,
可以采用 VisualVm的远程功能来进行,这需要使用tool.jar下的MAT功能。

1.1 常用linux分析命令

命令 作用与特点
vmstat 进程,虚拟内存,页面交换,IO读写,CPU活动等
iostat & iotop 系统IO状态信息
ifstat & iftop 实时网络流量监控
netstat 查看相关网络信息,各种网络协议套接字状态
dstat 全能型实时系统统计信息
strace 诊断,调试程序的系统调用
GDB 程序调试,coredump分析
lsof 查看系统当前打开的文件信息
tcpdump 网络抓包工具
traceroute 网络路由分析工具
jvm工具1--jmc.png
jvm工具2-btrace-线上问题定位神器.png

1.2 jvm 常用命令

1.2.1 jps:查看所有 Java 进程

jps(JVM Process Status):
显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一 ID(Local Virtual Machine Identifier,LVMID)。

jps -q :只输出进程的本地虚拟机唯一 ID。
jps -l: 输出主类的全名,如果进程执行的是 Jar 包,输出 Jar 路径。
jps -v:输出虚拟机进程启动时 JVM 参数。
jps -m:输出传递给 Java 进程 main() 函数的参数。

1.2.2 jmap:java 内存映射工具 (与 jhat 配合使用)

jmap(Memory Map for Java)命令用于生成堆转储快照。
打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。

如果不使用 jmap 命令,要想获取 Java 堆转储,
可以在启动时使用 -XX:+HeapDumpOnOutOfMemoryError 参数,
让虚拟机在 OOM 异常出现之后自动生成 dump 文件。

Linux 命令下可以通过 kill -3 发送进程退出信号也能拿到 dump 文件。

jmap 的作用并不仅仅是为了获取 dump 文件,
它还可以查询 finalizer 执行队列、Java 堆和永久代的详细信息,
如空间使用率、当前使用的是哪种收集器等。
和jinfo一样,jmap有不少功能在 Windows 平台下也是受限制的。
#命令格式: 
jmap [ option ] pid

#可选参数 [option]:
-dump:[live,]format=b,file= 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 
-finalizerinfo 打印正等候回收的对象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. 
-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. 
-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 
-h | -help 打印辅助信息 
-J 传递参数给jmap启动的jvm. 
#示例:
将指定应用程序的堆快照输出到桌面。
后面,可以通过 jhat、Visual VM 等工具分析该堆文件。
"jmap -dump:format=b,file=/heap.hprof 300"
jvm命令生成并分析dump文件1.png
jvm命令生成并分析dump文件2.png

1.2.3 jhat:jvm堆快照分析工具

jhat 命令与jamp搭配使用,用来分析map生产的堆快存储快照。jhat内置了一个微型http/Html服务器,可以在浏览器找那个查看。不过建议尽量不用,既然有dumpt文件,可以从生产环境拉取下来,然后通过本地可视化工具来分析,这样既减轻了线上服务器压力,有可以分析的足够详尽(比如 MAT/jprofile/visualVm)等。

1.2.4 jstack :java堆栈跟踪工具

jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照。
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合.
生成线程快照的目的主要是定位线程长时间出现停顿的原因,
如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的原因。
线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,
就可以知道没有响应的线程到底在后台做些什么事情,或者在等待些什么资源。
#命令格式:
jstack [ option ] pid

#可选参数 [option]
-F 当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l  长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m 打印java和native c/c++框架的所有栈信息.
-h | -help打印帮助信息
jstack--生成虚拟机当前时刻的线程快照.png

1.2.5 jstat: jvm统计信息监控工具

jstat(JVM Statistics Monitoring Tool)
使用于监视虚拟机各种运行状态信息的命令行工具。 
它可以显示本地或者远程(需要远程主机提供 RMI 支持)
虚拟机进程中的类信息、内存、垃圾收集、JIT 编译等运行数据,
在没有 GUI,只提供了纯文本控制台环境的服务器上,
它将是运行期间定位虚拟机性能问题的首选工具。

#jstat 命令使用格式:
jstat -
例子1: 收集gc信息,采样间隔时间为2000ms,收集5次.png

1.2.6 jinfo: 实时地查看和调整虚拟机各项配置参数

jinfo vmid :
输出当前 jvm 进程的全部参数和系统属性
第一部分是系统的属性,第二部分是 JVM 的参数。

#jinfo -flag  vmid :输出对应名称的参数的具体值。
jinfo -flag MaxTenuringThreshold 300
jinfo -flag MaxHeapSize 300
jinfo -flag PrintGC 300

#动态修改 jvm 的参数
使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。尤其在线上的环境特别有用
#jinfo -flag [+|-]name vmid 开启或者关闭对应名称的参数。
jinfo  -flag  +PrintGC 300
jinfo  -flag  PrintGC 300
jvm工具3-其他.png

1.3 常用分析工具

1.3.1 gc日志分析

如何获取gc日志

#For Java 1.4, 5, 6, 7, 8 pass this JVM argument to your application: 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+PrintGC
-XX:+PrintGCTimeStamps
-XX:+PriintHeapAtGC
-verbose:gc
-Xloggc:

#For Java 9, pass the JVM argument: 
-Xlog:gc*:file=

#注意
上述的 file-path: is the location where GC log file will be written

1.3.1.1 gceasy (在线分析)

https://blog.gceasy.io/

1.3.1.2 gcviewer (离线分析)

https://github.com/chewiebug/GCViewer (适于JDK高版本)
https://www.tagtraum.com/gcviewer.html (适于JDK低版本)

1.3.2 堆内存 dump 文件分析

如何获取堆内存 dump 文件

#1.应用启动时添加JVM参数
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/opt/appName/heapdump.hprof (可选)
-XX:-CreateMinidumpOnCrash (windows上使用)

#2.jmap, 不推荐, 因为线上应用时, 会导致GCPause
jmap -dump:format=b,file= 

#3.jcmd
jcmd  GC.heap_dump 

#4.JVisualVM图形工具采集

1.3.2.1 heaphero (在线分析)

https://blog.heaphero.io/

1.3.2.2 MAT(离线分析)

http://www.eclipse.org/mat/ (下载压缩版的)

1.3.3 线程 dump 文件(java-core)分析

如何获取线程 dump (java-core)文件

#1.jstack
jstack -l   >> 
如: jstack -l 37320 > /opt/tmp/threadDump.txt

#2.kill -3
kill -3 

#3.JVisualVM图形工具采集

1.3.3.1 fastthread (在线分析)

https://fastthread.io/

1.3.3.2 TMDA(离线分析)

https://www.ibm.com/support/pages/ibm-thread-and-monitor-dump-analyzer-java-tmda

1.3.4 国内综合分析工具(含JVM参数配置)

1.3.4.1 perfma (笨马网络)

https://www.perfma.com/

1.3.4.2 arthas

https://github.com/alibaba/arthas/blob/master/README_CN.md
https://gitee.com/arthas/arthas

1.3.5 JDK原生工具

#JVisualVM(最好配套下载各种插件, 如VisualGC):
JDK自带,功能强大,与JProfiler类似。推荐。

#Jconsole :
jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。

#JProfiler:
商业软件,需要付费。功能强大。

1.4 线上debug

jdb命令

1.5 线上问题不停机定位

btrace

2.实战部分

2.1 Windows上远程连接监控Linux服务器的JVM

#1、Linux服务器上配置:
在Tomcat的tomcat-wms/bin/catalina.sh中添加
CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=6090,server=y,suspend=n -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=192.168.0.199-Dcom.sun.management.jmxremote.port=8111 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:+UnlockCommercialFeatures -XX:+FlightRecorder"

#2、添加监控的配置:
在Tomcat的tomcat-wms/bin/catalina.sh中添加
JAVA_OPTS="
-server
-Xms8192m -Xmx8192m
-XX:+UseParallelOldGC
-XX:+UseAdaptiveSizePolicy
-XX:MaxGCPauseMillis=500
-XX:ParallelGCThreads=4
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UnlockDiagnosticVMOptions
-XX:+DebugNonSafepoints
-XX:NativeMemoryTracking=detail
-Denv_param=_simulation
-Xss2m
"

#3、在Windows端连接(见下图)
Java性能调优:利用JMC分析性能
在Windows端连接远程主机.png

2.2 cpu飙升

在线上有时候某个时刻,可能会出现应用某个时刻突然cpu飙升的问题。

step1:找到最耗CPU的进程: top -d 10

每10秒更新一次top,查看整体信息.png

step2:找到该进程下最耗费cpu的线程 top -Hp pid

step2:找到该进程下最耗费cpu的线程.png

step3:转换进制 printf "%x\n" 31236 (转换后为: 0x7a04)

step4:过滤指定线程,打印堆栈信息

#命令 
jstack pid |grep 'threadPid'  -C5 --color 
#示例(31214是进程pid, '0x7a04'是进程下一个子线程pid的16进制)
jstack 31214 |grep '0x7a04'  -C5 --color

2.4 java进程突然消失

1.如果JVM参数配置了宕机时生成dump文件,则查看相关文件,同时排查堆dump文件,线程dump文件,gc文件。

2.使用dmesg命令查看具体原因
sudo dmesg|grep -i kill|less
执行上述dmesg命令后,得到
"
[6710782.021013] java invoked oom-killer: gfp_mask=0xd0, order=0, oom_adj=0, oom_scoe_adj=0
[6710782.070639] [] ? oom_kill_process+0x68/0x140 
[6710782.257588] Task in /LXC011175068174 killed as a result of limit of /LXC011175068174 
[6710784.698347] Memory cgroup out of memory: Kill process 215701 (java) score 854 or sacrifice child 
[6710784.707978] Killed process 215701, UID 679, (java) total-vm:11017300kB, anon-rss:7152432kB, file-rss:1232kB
"
以上表明,对应的java进程被系统的OOM Killer给干掉了,得分为854。

解释一下OOM killer(Out-Of-Memory killer),该机制会监控机器的内存资源消耗。

当机器内存耗尽前,该机制会扫描所有的进程(按照一定规则计算,内存占用,时间等),挑选出得分最高的进程,然后杀死,从而保护机器。

dmesg 日志时间转换公式:

log实际时间=格林威治1970-01-01+(当前时间秒数-系统启动至今的秒数+dmesg打印的log时间)秒数:
date -d "1970-01-01 UTC `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+12288812.926194"|bc ` seconds"

剩下的就是看看是什么原因导致的OOM了。

参考资源
https://www.cnblogs.com/liuxl21/p/10763293.html (JMC监控远程主机)
https://www.cnblogs.com/liangzs/p/8489321.html (jvm内存快照dump文件太大)
https://www.jianshu.com/p/a49835c7f7ed (jvm 命令行小结)
https://mp.weixin.qq.com/s/hjwkmTm2Ze6qz7lnD8ThJw (问题分析)

你可能感兴趣的:(JVM系列(2) JVM监控工具)