Java平台,标准版故障排除指南:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/
1.设置Jvm进行故障排除(启用)
(1)将 -XX:+ HeapDumpOnOutOfMemoryError添加到jvm进程启动配置中,那么配置了该配置项,Java堆会将OutOfMemoryError相关内存溢出错误进行快照文件保存,我们可以配置导出文件 /dump文件夹中;示例如下
(2) Java Flight Recorder(JFR)启动飞行记录:就不详细描述了,因为商用收费。
设置Java以连续运行飞行记录。连续飞行记录是JFR事件的循环缓冲区。如果应用程序遇到问题,则可以转储运行最后一小时的数据。JFR事件对于调试从内存泄漏到网络错误,高CPU使用率,线程块等各种问题非常有用。
(3)将-verbosegc配置开启,那么将可以打印出JVM GC操作的日志:运行时间,内存变化之类;可以理解为这个是垃圾收集器日志;但是在大多数情况下,我们反而不会开启这个配置项,以线上经验来说,我们都是引入pinpoint作为监控工具,然后pinpoint内部将会记录所有的GC记录,并且详细到每个时间段的堆内存、非堆内存变化(一般来说:pinpoint最长7天日志会发生轮换)
此处需要注意日志轮换,因为在重启虚拟机进程后,日志会发生覆盖操作,那么我们需要增加一个配置:UseGClogFileRotation和
NumberOfGCLogFiles
(4)查询JDK版本,及虚拟机版本;
这需要引入一个Java执行命令了java -version
配置了全局变量,那么就可以直接在命令行中输入,否则只能通过进入JDK安装目录中的 /bin目录下了。
执行如下:
[root@localhost ~]# java -version
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
为什么需要确定JAVA版本号?以及JVM 类别呢?因为对于高速发展的JAVA,基本上每个版本中都会引入不同的新特性,对于JVM层的优化迭代,也是深度优化(如上图,笔者虚拟机为 HotSpot)
(5)引入工具JMC(Java Mission Control);
一个内存分析工具,
在我们的JDK目录下/bin/jmc.exe,win环境的话:直接双击启动即可,启动如下:
Oracle Java Mission Control 是什么? Oracle Java Mission Control 是一个用于对 Java 应用程序进行管理、监视、概要分析和故障排除的工具套件。首次安装时,Java Mission Control 包括 JMX 控制台和 Java 飞行记录器。从 Mission Control 中可以轻松安装更多插件。
具体使用,此处不赘述,后面单独的叙述
此处引出一个新的的jvm命令(可以动态的与JVM内存进行交互查询)
官方文档超链接:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html#BABEHABG
jcmd
命令执行效果如下:
[root@changemax-wangji bin]# jcmd
3736539 org.elasticsearch.bootstrap.Elasticsearch -d
2750864 /opt/server/cm-network-squirrel-server/jar/cm-network-squirrel-server.jar --server.port=18000 -Dfile.encoding=UTF-8
666005 sun.tools.jcmd.JCmd
然后,我们选择对应的进程PID,进行 jcmd <pid> help
[root@changemax-wangji bin]# jcmd 2750864 help
2750864:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
VM.classloader_stats
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.finalizer_info
GC.heap_info
GC.run_finalization
GC.run
VM.uptime
VM.dynlibs
VM.flags
VM.system_properties
VM.command_line
VM.version
help
For more information about a specific command use 'help <command>'.
就可以手动执行GC之类的指令了(试一试查询VM版本、手动GC)
1.打印所有线程
[root@changemax-wangji bin]# jcmd 2750864 Thread.print
2750864:
2020-12-07 14:24:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.261-b12 mixed mode):
........
# 好多线程阻塞什么的信息,此处不贴出来了;
2.查询虚拟机版本
[root@changemax-wangji bin]# jcmd 2750864 VM.version
2750864:
Java HotSpot(TM) 64-Bit Server VM version 25.261-b12
JDK 8.0_261
3.手动进行GC
[root@changemax-wangji bin]# jcmd 2750864 GC.run
2750864:
Command executed successfully
4.打印虚拟机所有系统配置信息
[root@localhost ~]# jcmd 752 VM.system_properties;
752:
#Mon Dec 07 14:35:41 CST 2020
java.runtime.name=Java(TM) SE Runtime Environment
java.protocol.handler.pkgs=org.springframework.boot.loader
sun.boot.library.path=/usr/java/jdk1.8.0_92/jre/lib/amd64
java.vm.version=25.92-b14
java.vm.vendor=Oracle Corporation
java.vendor.url=http\://java.oracle.com/
path.separator=\:
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg=sun.io
user.country=US
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=unknown
java.vm.specification.name=Java Virtual Machine Specification
user.dir=/opt/xuehaiserver/spam-filter-service/bin
PID=752
java.runtime.version=1.8.0_92-b14
5.打印虚拟机所有配置信息(JVM相关)
[root@localhost ~]# jcmd 752 VM.flags;
752:
-XX:CICompilerCount=2 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/xxxx/xxxxx-service/dump/ -XX:InitialHeapSize=1073741824 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=357564416 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=357564416 -XX:OldSize=716177408 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
6.以秒为单位打印正常运行时间(这个服务运行27.8721041 天了)
[root@localhost ~]# jcmd 752 VM.uptime
752:
2408149.790 s
7.创建类直方图(本质来说,就是打印所有类之间的应用关系)
执行结果太多,此处不贴出
jcmd <process id/main class> GC.class_histogram
8.创建堆转储(hprof dump)(就是将当前堆内存的使用情况,建立一个快照文件,那么这个快照文件就可以通过JMC进行打卡)
[root@localhost ~]# jcmd 752 GC.heap_dump filename=/opt/wangji/dump/heapDump
752:
Heap dump file created
9.创建类直方图转存(本质来说,就是获取所有类之间的应用关系)
jcmd <process id/main class> GC.class_histogram filename=Myheaphistogram
线上问题排查jcmd命令
1.进行内存录制命令
[root@localhost ~]# jcmd 752 JFR.start name=MyRecording settings=profile delay=20s duration=2m filename=/opt/wangji-jfr.jfr
752:
Java Flight Recorder not enabled.
Use VM.unlock_commercial_features to enable.
#很明显,没有启用飞行器,该功能为商用。。。
2.启用诊断命令,诊断正在运行的飞行器
[root@localhost ~]# jcmd 752 JFR.check
752:
Java Flight Recorder not enabled.
Use VM.unlock_commercial_features to enable.
#很明显,没有启用飞行器,该功能为商用。。。
3.停止飞行器功能
[root@localhost ~]# jcmd 752 JFR.stop
752:
Java Flight Recorder not enabled.
Use VM.unlock_commercial_features to enable.
//上面所述的转存堆内存快照、类直方图,都是可以用于线上问题定位的
2.那么对于我们进行线上问题排查的话,还有哪些准备工作呢?第一个,就是需要收集线上相关的数据:日志文件、奔溃核心文件、堆内存快照、Java飞行记录(转存)、堆栈跟踪记录(相关命令为:Thread.print);当然,大部分情况来说,我们服务层都会将错误日志进行打印,那么对于虚拟机层面来说,对于程序员门槛较高,不是很可取的一种方案。但是作为一个有志气的程序员,也是会这些的。