“这是我参加11月更新挑战赛的第9天,活动详情请查看:2021最后更新挑战赛。”
定位系统问题时,知识和经验是关键依据,数据是基础。 工具是应用知识来处理数据的手段。 这里提到的数据包括:运行日志、异常栈、GC日志、线程快照文件(/files)、堆转储快照(/hprof文件)等。使用JVM命令,查看JVM参数可以帮助我们排查和解决问题。
1 JDK命令行工具
JDK的大部分命令行工具只是对JDK/lib/tools.jar类库的一层薄薄的包装,它们的主要功能代码都在tools类库中实现。 Linux下的一些工具甚至是用shell脚本编写的。
常用工具如下:
姓名
主效应
太平绅士
JVM Tool,显示指定系统中所有虚拟机进程
统计数据
JVM Tool,用于收集虚拟机各方面的运行数据
金佛
Info for Java,显示虚拟机配置信息
杰图
Map for Java,生成虚拟机内存转储快照(文件)
贾特
JVM Heap Dump,分析文件,并在浏览器中查看结果
java 的堆栈跟踪,显示虚拟机的线程快照
1.1 jps——虚拟机进程状态工具
列出正在运行的虚拟机进程,并显示这些进程的虚拟机执行主类名称和本地虚拟机唯一 ID。
jps命令格式:
jps [ ] [ ]
jps可以通过RMI协议打开RMI服务的远程虚拟机进程状态,即RMI注册表中注册的主机名。
jps常用选项:
选项
影响
-q
只输出LVMID
-m
输出虚拟机进程启动时传递给主类main()函数的参数
-l
输出主类全名,如果进程执行jar包,则输出jar路径
-v
虚拟机进程启动时输出JVM参数
1.1.1 案例
案例类如下
public class Jstat {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000000);
}
}
复制代码
运行后,使用jps命令显示虚拟机进程id和名称:
1.2 jstat——虚拟机统计工具监控工具
jstat是一个命令行工具,用于监控虚拟机的各种运行状态信息。 它可以显示本地或远程虚拟机进程中的类加载、内存、垃圾回收、JIT编译等运行数据。 解决机器性能问题的首选工具。
jstat的命令格式:
jstat [ vmid [ [s|ms] [count]] ]
:参数选项 -t:可以在打印列中添加一列,显示系统的运行时间 -h:指定数据周期时输出的行数后,可以输出一次表头vmid:ID(进程pid): 每次执行的时间间隔,单位毫秒 count: 用于指定输出多少条记录,默认会一直打印。 对于命令格式中的VMID和LVMID来说,如果是本地虚拟机进程,VMID和LVMID是一致的。 如果是远程虚拟机,VMID的格式应该是:[:][//] lvmid[@[:port]/] 参数和count分别代表查询的间隔和次数。 如果省略这两个参数,表示只执行一次查询。
jstat常用选项:
选项
影响
-班级
加载的类数量、卸载数量、总空间、类状态消耗的时间
-GC
监控Java堆容量状态,包括Eden、老年代、永久代等。
-
监控Java堆最大和最小空间
-
关注已用空间占总空间的百分比
-
同样,额外输出上次GC的原因
-GC新
新生代GC状态
-
与-GCnew类似,输出重点关注使用的最大和最小空间
-GCold
老年代GC状态
-
与-GCold类似,输出重点关注已使用的最大和最小空间
-
输出永久代使用的最大和最小空间
-
输出JIT编译的方法和耗时
-
经过 JIT 编译的输出方法
-
元数据空间统计
1.2.1 案例
添加-GC以显示GC堆信息。 还是用前面的例子,设置VM参数为- - -,即初始内存为30m,最大内存为30m,年轻代为10m。
运行程序,使用jstat -gc 6128命令,结果如下,可以看到GC堆信息:
S0C:年轻代中第一个(生存区)的容量(字节) S1C:年轻代中第二个(生存区)的容量(字节) S0U:年轻代中第一个(生存区)当前的容量已使用空间(字节) S1U:年轻代中第二个(生存区)当前已使用空间(字节) EC:年轻代中伊甸园(Eden)的容量(字节) EU:年轻代中伊甸园(Eden)当前使用的空间(字节) OC:老年代容量(字节) OU:老年代当前使用的空间(字节) MC:(元空间)容量(字节) MU:(元空间)当前使用的空间(字节) YGC:从应用程序启动到采样时间年轻代中的GC次数 YGCT:从应用程序启动到采样时间在年轻代中使用的GC时间(秒) FGC:从应用程序启动到在年老代中采样的时间(完整) GC) GC times FGCT:老年代(full GC) GC 从应用启动到采样所用的时间(s) GCT:从应用启动到 GC 使用的总时间(s)取样
从图中可以看出,结果符合我们VM参数设置的信息。
1.3 jinfo——Java配置信息工具
实时查看和调整虚拟机的各种参数。
jinfo常用选项:
选项
影响
案子
-旗帜
调整虚拟机参数
金信息-标志 + 1479
-标志
查看指定进程的所有参数
金信息-标志 1479
-
打印虚拟机进程系统内容
金佛-1479
无参考
打印全部
金佛1479
1.3.1 案例
使用上面的例子,加上vm参数信息- - -。 使用jinfo -flags 6128,可以从结果中找到我们设置的vm信息。
1.4 jmap——Java内存映射工具
jmap 命令用于生成堆转储快照。 jmap的作用不仅仅是获取dump文件,还可以查询执行队列、java堆、永久代的详细信息。 比如空间使用情况、当前使用的是哪个收集器等。
jmap格式:
jmap [] vmid
jmap常用选项:
选项
影响
-倾倒
生成格式为 -dump:[live,]=b,file= 的堆转储快照,不推荐
-
显示在 F 队列中等待线程执行方法的对象
-堆
显示java堆详细信息、收集器类型、参数配置、分代状态等
-历史
显示堆中对象的统计信息,包括类、实例数和总容量。 它会先触发GC,然后再统计信息。 不建议使用
-
查看永久代的内存状态非常耗时,并且会挂起应用程序。 不建议使用
-F
强制生成转储快照,并在 -dump 失败时再次使用此命令
1.4.1 案例
还是上面的例子。
使用jmap -heap 6128,可以看到我们VM参数设置的信息:
jmap -dump:live,=b,file=C:\Users\lx\\test1.bin 9472
会生成一个堆转储快照,这里我生成到桌面。 稍后您可以使用 jhat 来分析转储文件。
1.5 jhat——虚拟机堆快照分析工具
Sun JDK提供了jhat和jmap一起使用来分析dump生成的堆快照。 jhat内置了一个微型HTTP/HTML服务器,生成转储文件的分析结果后,您可以在浏览器中查看它。
1.5.1 案例
jhat test1.bin
test1.bin是上面生成的转储文件。 提示“已准备好”后。 屏幕上显示,用户在浏览器中输入:7000 即可看到分析结果。
默认情况下,分析结果以包为单位进行分组显示,内存泄漏的分析将主要使用“Heap”和OQL标签的功能。 前者可以找到内存中总容量最大的对象。 后者是一种标准的对象查询语言,它使用类似SQL的语法来查询和统计内存中的对象。
1.6 - Java 堆栈跟踪工具
该命令用于生成虚拟机当前时刻的线程快照(一般称为或文件)。 线程快照是当前虚拟机中每个线程正在执行的方法堆栈的集合。 生成线程快照的主要目的是定位线程长时间停顿的原因,例如线程死锁、死循环、请求外部资源导致的长时间等待等。
格式:
[] vmid
常用选项:
选项
影响
案子
-m
如果调用本机方法,则显示 C/C++ 堆栈
-m 1479
-l
除了堆栈之外,还显示有关锁的其他信息
-l 1479
-F
当正常输出的请求没有得到响应时,强制输出线程堆栈
-F 1479
1.6.1 案例
-l 9472
会输出很多信息,我们可以找到以下信息:
可以看到,主线程正在等待一个时间限制——因为sleep。
它可以帮助我们分析线程信息,比如死锁、状态等。
2 JDK可视化工具
JDK中除了提供大量的命令行工具外,还有两个强大的可视化工具:and,这两个工具是JDK的正式成员,不标注“和”。
2.1 - Java监控和管理控制台
从 Java 5 开始引入,是一个内置的 Java 性能分析器。 您可以轻松地使用它(或其高端“近亲”)来监视 Java 应用程序性能并跟踪 Java 中的代码。 (建议使用升级版本)
2.2 ——一体化的故障排除工具
是一个集成了多个JDK命令行工具的可视化工具。 基于平台开发,具有插件扩展功能的特点。 通过插件的扩展,可以用来显示虚拟机进程及进程的配置和环境信息(jps、jinfo)、监控应用程序CPU、GC、堆、方法区和线程信息(jstat、)等。 在JDK/bin目录下。
以上两个工具的使用可以看这篇文章:Java死锁详解及解决方案。 其中的死锁检测部分指导了这两个工具的使用。
3 其他外部工具
除了JDK自带的工具之外,使用外部工具可以为我们提供更强大的功能。
3.1 MAT——内存分析工具
MAT(Tool)是基于MAT的内存分析工具,是一个快速且功能丰富的JAVA堆分析工具,可以帮助我们发现内存泄漏,减少内存消耗。 使用内存分析工具从众多对象中进行分析,快速计算出内存中对象的大小,看看是谁阻止了垃圾收集器的回收,并可以通过报告对象直观地查看可能的结果。
官网地址:
3.3.1 下载并安装
下载链接:…
解压下载的-1.8.0.-win32.win32..zip:
双击开始!
3.3.2 使用
转储文件只是一个快照文件。 您可以使用jmap、VM等工具导出转储文件。 MAT还可以直接导出转储文件。 当然,您也可以直接打开现有的转储文件。
查看对象及其依赖关系:
检查可能的内存问题的分析:
3.3.3 案例 3.3.3.1 内存溢出代码
编写代码向 List 集合添加 100 万个字符串,每个字符串由 1000 个 UUID 组成。 如果程序能够正常执行,最后打印ok。
vm参数设置为-Xms4m -Xmx4m -XX:+参数表示当JVM OOM发生时,自动生成DUMP文件。
public class TestJvmOutOfMemory {
public static void main(String[] args) {
List
3.3.3.2 运行测试
结果如下:
可以看出发生了内存溢出。 当发生内存溢出时,转储文件.hprof将在项目目录中:
3.3.3.3 导入MAT工具进行分析
可以看到70.27%的内存被[]数组占用,因此很可疑,很有可能导致内存溢出。