6 款 Java 8 自带工具,轻松分析定位 JVM 问题

这篇文章中介绍下如何使用 JDK 自带工具来分析和定位 JAVA 程序的问题 。
使用 JDK 自带工具查看 JVM 情况
JDK 自带了很多命令行甚至是图形界面工具,帮助我们查看 JVM 的一些信息 。比如,在我的机器上运行 ls 命令,可以看到 JDK 8 提供了非常多的工具或程序:

6 款 Java 8 自带工具,轻松分析定位 JVM 问题

文章插图
 
接下来,我会与你介绍些常用的监控工具 。你也可以先通过下面这张图了解下各种工具的基本作用:
6 款 Java 8 自带工具,轻松分析定位 JVM 问题

文章插图
 
为了测试这些工具,我们先来写一段代码:启动 10 个死循环的线程,每个线程分配一个 10MB 左右的字符串,然后休眠 10 秒 。可以想象到,这个程序会对 GC 造成压力:
//启动10个线程IntStream.rangeClosed(1, 10).mapToObj(i -> new Thread(() -> {while (true) {//每一个线程都是一个死循环,休眠10秒,打印10M数据String payload = IntStream.rangeClosed(1, 10000000).mapToObj(__ -> "a").collect(Collectors.joining("")) + UUID.randomUUID().toString();try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(payload.length());}})).forEach(Thread::start);TimeUnit.HOURS.sleep(1);修改 pom.xml,配置 spring-boot-maven-plugin 插件打包的 Java 程序的 main 方法类:
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication</mainClass></configuration></plugin>然后使用 java -jar 启动进程,设置 JVM 参数,让堆最小最大都是 1GB:
【6 款 Java 8 自带工具,轻松分析定位 JVM 问题】java -jar common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g完成这些准备工作后,我们就可以使用 JDK 提供的工具,来观察分析这个测试程序了 。
jps
首先,使用 jps 得到 Java 进程列表,这会比使用 ps 来的方便:
?~ jps1270722261 Launcher23864 common-mistakes-0.0.1-SNAPSHOT.jar15608 RemoteMavenServer3623243 Main23868 Jps22893 KotlinCompileDaemonjinfo
然后,可以使用 jinfo 打印 JVM 的各种参数:
?~ jinfo 23864Java System Properties:#Wed Jan 29 12:49:47 CST 2020...user.name=zhuyepath.separator=:os.version=10.15.2java.runtime.name=Java(TM) SE Runtime Environmentfile.encoding=UTF-8java.vm.name=Java HotSpot(TM) 64-Bit Server VM...VM Flags:-XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=8 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=268435456 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4294967296 -XX:MaxNewSize=2576351232 -XX:MinHeapDeltaBytes=1048576 -XX:NonNMethodCodeHeapSize=5835340 -XX:NonProfiledCodeHeapSize=122911450 -XX:ProfiledCodeHeapSize=122911450 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GCVM Arguments:java_command: common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1gjava_class_path (initial): common-mistakes-0.0.1-SNAPSHOT.jarLauncher Type: SUN_STANDARD查看第 15 行和 19 行可以发现,我们设置 JVM 参数的方式不对,-Xms1g 和 -Xmx1g 这两个参数被当成了 Java 程序的启动参数,整个 JVM 目前最大内存是 4GB 左右,而不是 1GB 。最近整理了一份最新的面试资料,里面收录了2021年各个大厂的面试题,打算跳槽的小伙伴不要错过,点击领取吧!
因此,当我们怀疑 JVM 的配置很不正常的时候,要第一时间使用工具来确认参数 。除了使用工具确认 JVM 参数外,你也可以打印 VM 参数和程序参数:
System.out.println("VM options");System.out.println(ManagementFactory.getRuntimeMXBean().getInputArguments().stream().collect(Collectors.joining(System.lineSeparator())));System.out.println("Program arguments");System.out.println(Arrays.stream(args).collect(Collectors.joining(System.lineSeparator())));把 JVM 参数放到 -jar 之前,重新启动程序,可以看到如下输出,从输出也可以确认这次 JVM 参数的配置正确了:
?target git:(master) ? java -Xms1g -Xmx1g -jar common-mistakes-0.0.1-SNAPSHOT.jar testVM options-Xms1g-Xmx1gProgram argumentstestjvisualvm
然后,启动另一个重量级工具 jvisualvm 观察一下程序,可以在概述面板再次确认 JVM 参数设置成功了:
6 款 Java 8 自带工具,轻松分析定位 JVM 问题

文章插图
 
继续观察监视面板可以看到,JVM 的 GC 活动基本是 10 秒发生一次,堆内存在 250MB 到 900MB 之间波动,活动线程数是 22 。我们可以在监视面板看到 JVM 的基本情况,也可以直接在这里进行手动 GC 和堆 Dump 操作:


推荐阅读