当前位置: 首页 > 科技观察

JVM:可视化JVM故障排除工具

时间:2023-03-13 12:57:39 科技观察

1。可视化工具在JDK中为我们提供了大量的JVM排错工具,都在JDK的bin目录下:除了大量的命令行工具,它还为我们提供了更加方便快捷的可视化工具,主要有以下四种:JConsole:最古老的工具,早在JDK5时期就有的虚拟机监控工具。JHSDB:名义上只在JDK9中正式提供,但在sa-jdi.jar包中以HSDB(可视化工具)和CLHSDB(命令行工具)的形式存在了很长时间。VisualVM:最早发布于JDK6Update7,直到完成JRockitMissionControl和OracleJDK的集成,是Oracle推动的一体式故障处理工具,现在已经从OracleJDK中分离出来,成为一个独立开发的开源项目。JMC:JavaMissionControl曾经是BEA著名的图形诊断工具,随着BEA被Oracle收购,它被集成到OracleJDK中。它在JDK7Update40中与JDK一起发布。后来,建立了JavaSEAdvanced产品线。Oracle明确区分了OracleOpenJDK和OracleJDK的区别。JMC从JDK11开始从JDK中移除。2.HSDBHSDB(HotspotDebugger)是JDK自带的一个工具,用于查看JVM运行时的状态。JDK9之前官方没有提供使用方法,所以在JDK的bin目录下没有提供直接的可执行文件,需要在命令行执行命令才能启动。首先在命令行cd到C:\ProgramFiles\Java\jdk1.8.0_221\lib目录下,然后执行:java-cp.\sa-jdi.jarsun.jvm.hotspot.HSDB我是执行这个命令报错:Exceptioninthread"Thread-1"java.lang.UnsatisfiedLinkError:Can'tloadlibrary:C:\ProgramFiles\Java\jdk-11.0.4\bin\sawindbg.dllatjava.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2620)atjava.base/java.lang.Runtime.load0(Runtime.java:767)atjava.base/java.lang.System.load(System.java:1831)atsun.jvm.hotspot.debugger。windbg.WindbgDebuggerLocal.(WindbgDebuggerLocal.java:661)atsun.jvm.hotspot.HotSpotAgent.setupDebuggerWin32(HotSpotAgent.java:567)atsun.jvm.hotspot.HotSpotAgent.setupDebugger(HotSpotAgent.java:335).atsun.jvmhotspot.HotSpotAgent.go(HotSpotAgent.java:304)atsun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:140)atsun.jvm.hotspot.HSDB.attach(HSDB.java:1184)atsun.jvm.hotspot。HSDB.access$1700(HSDB.java:53)atsun.jvm.hotspot.HSDB$25$1.run(HSDB.java:456)atsun.jvm.hotspot.utilities.WorkerThread$MainLoop.run(WorkerThread.java:66)atjava.base/java.lang.Thread.run(Thread.java:834)意思是jdk目录下有一个sawindbg.dll是找不到的,因为我本地有多个jdk,配置环境变量是jdk11,我在jdk8的jre的bin目录下找到这个文件,直接复制到jdk11的bin目录下就解决了这个问题执行完成后会打开这样一个界面:接下来我们写一小段测试代码:(){System.out.println("IamBclass");}}publicclassHSDB_Test{publicstaticvoidmain(String[]args)throwsIOException{Aobj=newB();//无意义,只是用来阻塞主线程,防止线程结束System.in.read();System.out.println(obj);}}首先在命令行使用命令jps-l查看Java进程的pid:PSC:\Users\inwsy>jps-l1648com.geekdigging.lesson04.jvmtools.HSDB_Test87049280org.jetbrains.jps.cmdline.Launcher14724jdk.jcmd/sun.tools.jps.Jps3220org/netbeans/Main1514420572org.jetbrains.jps.cmdline.Launcher7548pidsun.jvm.hotspot你可以看到HSDB我们刚才写的测试方法是1648,在HSDB中点击File>AttachtoHotspotprocess:首先看到的是curre中的threadnt进程:到这里,我们的准备工作就结束了,接下来我们使用Tools>ClassBrowser找到对象B的内存地址:图中红框框出的是我自己写的三个类。可以看到这里B的内存地址是0x00000007c0060c18。接下来使用Tools>Inspector查看这个对象的详细信息:vtable是一个虚表方法,这里我们看到B类有7个虚表方法,因为所有对象都继承自Object,所以B继承了5个Object方法,以及然后继承了A的一个方法,又自己重写了一个方法,一共7个方法。我们可以通过在Windows>Console中使用mem命令查看来验证这一点。然后我们就可以开始计算了,vtable在instanceKlass对象实例的末尾,而instanceKlass的大小在64位系统中是0x1B8,所以vtable的起始地址等于instanceKlass的首内存地址加上0x1B8,等于7C0060DD0。接下来我们在Windows>Console中使用mem命令验证:第一列是方法在堆中的实际内存地址,第二列是内存指针地址。我们可以将获取到的内存指针地址分别传递给A、B和Object,可以看到前5行对应的是Object的方法,第6行对应的是A对象的方法,第7行对应的是方法B对象。3、JConsoleJConsole(JavaMonitoringandManagementConsole)是一个基于JMX(JavaManagement-mentExtensions)的可视化监控管理工具。它的主要功能是通过JMX的MBean(ManagedBean)收集信息,动态调整系统参数。JConsole位于JDK/bin目录下,双击jconsole.exe即可直接启动。启动后会自动搜索本机当前运行的所有虚拟机进程。在这里你可以看到我当前正在运行一个JConsole,一个idea,以及一个启动的tomcat的源代码。任意双击一个服务进入主页面:可以看到主界面包括六个选项卡:overview、memory、thread、class、VMsummary、MBean。下面举个小例子,来了解一下它的监控功能。publicclassMonitoringTest{//内存占用对象,一个64KB左右的对象staticclassOOMObject{publicbyte[]placeholder=newbyte[64*1024];}publicstaticvoidfillHeap(intnums)throwsInterruptedException{Listlist=newArrayList<>();for(inti=0;iPlugins中安装VisualVM插件即可。我这里只安装了两个最常用的,一个是GC监控插件,一个是可以动态插入调试器的插件。这里我使用最常用的开发工具IDEA,通过VisualVM监控程序GC来演示启动过程。首先我们启动IDEA,直到IDEA可以正常运行,再看VisualVM的GC监控。在主信息面板可以看到IDEA使用的JVM的版本信息,可以看到具体的JAVA_HOME路径,还可以看到具体的JVM参数。这里可以看到IDEA启动时默认设置的最小堆内存和最大堆内存分别设置为128MB和750MB,使用的垃圾收集器是CMS收集器。然后点击VisualGC,可以看到在启动过程中,Class加载大约用了28s,而Class编译用了35s。而在这个过程中,MinorGC被触发了149次,消耗只有713ms。我们比较关注的FullGC没有触发一次,消耗为0。因为IDEA默认使用的是CMS收集器,所以我们换成G1收集器会不会更快呢?首先找到IDEA的配置文件。我的IDEA是通过Toolbox安装的,所以我的IDEA配置文件的路径有点奇怪。D:\ProgramFiles\JetBrains\apps\IDEA-U\ch-0\202.7660.26.vmoptions。先把这个文件备份到桌面,防止IDEA损坏无法使用。删除现有的垃圾收集器配置-XX:+UseConcMarkSweepGC,添加G1收集器的配置:-XX:+UseG1GC其余配置不做修改,关闭IDEA重启,再查看GC情况。先看主面板看我们的GC收集器是否切换成功:再看GC面板:MinorGC被触发了271次,消耗达到了853ms。嗯,看来客户端还是用CMS做垃圾收集器比较合适。我们再次修改-Xmx配置,将配置的大小减少到当前大小的一半,然后将GC改回原来的CMS,查看FullGC的情况:可以看到FullGC发生了46次times,andconsumes时间超过了21s,这就是IDEA界面也开始弹出警告,警告我们内存不足,需要调整。吓得赶紧改回原来的配置,顺便把-Xmx的size调大到1024,尽量减少FullGC的发生。4、JavaMissionControlJMC也在JDK/bin目录下,双击jmc.exe运行。打开后在JVM浏览器面板有两个选项,一个是MBean,一个是JFRflightrecorder。关于MBean的数据和从JConsole和VisualVM中获取的内容是一样的,只是显示形式有些不同,就不多说了。双击“FlightRecorder”,会出现“FlightRecorder”窗口(如果是第一次使用,也会收到解锁商业功能的警告窗口)。注意:使用前需要在JVM中加入以下两个参数,意思是解开JFR函数的锁。-XX:+UnlockCommercialFeatures-XX:+FlightRecorder飞行记录报告包含以下几类信息:一般信息:关于虚拟机、操作系统和记录的一般信息。内存:关于内存管理和垃圾回收的信息。代码:有关方法、异常错误、编译和类加载的信息。线程:有关应用程序中线程和锁的信息。I/O:有关文件和套接字输入和输出的信息。系统:关于Java虚拟机运行的系统、进程和环境变量的信息。事件:记录中有关事件类型的信息,可以按线程或堆栈跟踪以日志或图形格式查看。5.总结看这4个可视化工具,个人感觉最后一个JMC对用户最友好。MBean数据源展示了大量当前的JVM信息,并且全部以图表的形式展现。它更强大。它的JFR功能可以记录一段时间内的所有操作,并以图表的形式展示出来,这对我们分析问题无疑有很大的帮助。当然,您喜欢使用哪种工具完全是个人喜好。例如,VisualVM也很强大。它可能没有那么强的功能,但是它可以安装插件,你完全可以根据自己的需要安装插件。这个方法非常DIY,我还是更喜欢使用VisualVM一些。