【Java开发日记】6个Java 工具,轻松分析定位 JVM 问题 !

article/2025/6/20 12:04:49

目录

使用 JDK 自带工具查看 JVM 情况

jps

jinfo

jvisualvm

jcm


使用 JDK 自带工具查看 JVM 情况

JDK 自带了很多命令行甚至是图形界面工具,帮助查看 JVM 的一些信息。比如,在机器上运行 ls 命令,可以看到 JDK 8 提供了非常多的工具或程序:
 

接下来介绍些常用的监控工具。也可以先通过下面这张图了解下各种工具的基本作用:

为了测试这些工具,先来写一段代码:启动 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:

java -jar common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g

完成这些准备工作后,就可以使用 JDK 提供的工具,来观察分析这个测试程序了。 

jps

首先,使用 jps 得到 Java 进程列表,这会比使用 ps 来的方便:

➜  ~ jps
12707
22261 Launcher
23864 common-mistakes-0.0.1-SNAPSHOT.jar
15608 RemoteMavenServer36
23243 Main
23868 Jps
22893 KotlinCompileDaemon

jinfo

然后,可以使用 jinfo 打印 JVM 的各种参数:

➜  ~ jinfo 23864
Java System Properties:
#Wed Jan 29 12:49:47 CST 2020
...
user.name=zhuye
path.separator=\:
os.version=10.15.2
java.runtime.name=Java(TM) SE Runtime Environment
file.encoding=UTF-8
java.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:+UseG1GC
VM Arguments:
java_command: common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g
java_class_path (initial): common-mistakes-0.0.1-SNAPSHOT.jar
Launcher Type: SUN_STANDARD

查看第 15 行和 19 行可以发现,设置 JVM 参数的方式不对,**-Xms1g** 和 **-Xmx1g** 这两个参数被当成了 Java 程序的启动参数,整个 JVM 目前最大内存是 4GB 左右,而不是 1GB。
因此,当怀疑 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 test
VM options
-Xms1g
-Xmx1g
Program arguments
test

jvisualvm

然后,启动另一个重量级工具 jvisualvm 观察一下程序,可以在概述面板再次确认 JVM 参数设置成功了:

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

jconsole如果希望看到各个内存区的 GC 曲线图,可以使用 jconsole 观察。jconsole 也是一个综合性图形界面监控工具,比 jvisualvm 更方便的一点是,可以用曲线的形式监控各种数据,包括 MBean 中的属性值:

 jstat

同样,如果没有条件使用图形界面(毕竟在 Linux 服务器上,主要使用命令行工具),又希望看到 GC 趋势的话,可以使用 jstat 工具。
jstat 工具允许以固定的监控频次输出 JVM 的各种监控指标,比如使用 -gcutil 输出 GC 和内存占用汇总信息,每隔 5 秒输出一次,输出 100 次,可以看到 Young GC 比较频繁,而 Full GC 基本 10 秒一次:

➜  ~ jstat -gcutil 23940 5000 100S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT0.00 100.00   0.36  87.63  94.30  81.06    539   14.021    33    3.972   837    0.976   18.9680.00 100.00   0.60  69.51  94.30  81.06    540   14.029    33    3.972   839    0.978   18.9790.00   0.00   0.50  99.81  94.27  81.03    548   14.143    34    4.002   840    0.981   19.1260.00 100.00   0.59  70.47  94.27  81.03    549   14.177    34    4.002   844    0.985   19.1640.00 100.00   0.57  99.85  94.32  81.09    550   14.204    34    4.002   845    0.990   19.1960.00 100.00   0.65  77.69  94.32  81.09    559   14.469    36    4.198   847    0.993   19.6590.00 100.00   0.65  77.69  94.32  81.09    559   14.469    36    4.198   847    0.993   19.6590.00 100.00   0.70  35.54  94.32  81.09    567   14.763    37    4.378   853    1.001   20.1420.00 100.00   0.70  41.22  94.32  81.09    567   14.763    37    4.378   853    1.001   20.1420.00 100.00   1.89  96.76  94.32  81.09    574   14.943    38    4.487   859    1.007   20.4380.00 100.00   1.39  39.20  94.32  81.09    575   14.946    38    4.487   861    1.010   20.442

其中,S0 表示 Survivor0 区占用百分比,S1 表示 Survivor1 区占用百分比,E 表示 Eden 区占用百分比,O 表示老年代占用百分比,M 表示元数据区占用百分比,YGC 表示年轻代回收次数,YGCT 表示年轻代回收耗时,FGC 表示老年代回收次数,FGCT 表示老年代回收耗时。
jstat 命令的参数众多,包含 -class-compiler-gc 等。Java 8、Linux/Unix 平台 jstat 工具的完整介绍,可以查看这里。jstat 定时输出的特性,可以方便持续观察程序的各项指标。
继续来到线程面板可以看到,大量以 Thread 开头的线程基本都是有节奏的 10 秒运行一下,其他时间都在休眠,和代码逻辑匹配:

点击面板的线程 Dump 按钮,可以查看线程瞬时的线程栈:

 jstack

通过命令行工具 jstack,也可以实现抓取线程栈的操作:

➜  ~ jstack 23940
2020-01-29 13:08:15
Full thread dump Java HotSpot(TM) 64-Bit Server VM (11.0.3+12-LTS mixed mode):
...
"main" #1 prio=5 os_prio=31 cpu=440.66ms elapsed=574.86s tid=0x00007ffdd9800000 nid=0x2803 waiting on condition  [0x0000700003849000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@11.0.3/Native Method)
at java.lang.Thread.sleep(java.base@11.0.3/Thread.java:339)
at java.util.concurrent.TimeUnit.sleep(java.base@11.0.3/TimeUnit.java:446)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication.main(CommonMistakesApplication.java:41)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.3/Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.3/NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.3/DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(java.base@11.0.3/Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
"Thread-1" #13 prio=5 os_prio=31 cpu=17851.77ms elapsed=574.41s tid=0x00007ffdda029000 nid=0x9803 waiting on condition  [0x000070000539d000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@11.0.3/Native Method)
at java.lang.Thread.sleep(java.base@11.0.3/Thread.java:339)
at java.util.concurrent.TimeUnit.sleep(java.base@11.0.3/TimeUnit.java:446)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication.lambda$null$1(CommonMistakesApplication.java:33)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication$$Lambda$41/0x00000008000a8c40.run(Unknown Source)
at java.lang.Thread.run(java.base@11.0.3/Thread.java:834)
...

抓取后可以使用类似fastthread(https://fastthread.io/)这样的在线分析工具来分析线程栈。 

jcmd

最后,来看一下 Java HotSpot 虚拟机的 NMT 功能。
通过 NMT,可以观察细粒度内存使用情况,设置 -XX:NativeMemoryTracking=summary/detail 可以开启 NMT 功能,开启后可以使用 jcmd 工具查看 NMT 数据。
重新启动一次程序,这次加上 JVM 参数以 detail 方式开启 NMT:

-Xms1g -Xmx1g -XX:ThreadStackSize=256k -XX:NativeMemoryTracking=detail

在这里,还增加了 -XX:ThreadStackSize 参数,并将其值设置为 256k,也就是期望把线程栈设置为 256KB。通过 NMT 观察一下设置是否成功。
启动程序后执行如下 jcmd 命令,以概要形式输出 NMT 结果。可以看到,当前有 32 个线程,线程栈总共保留了差不多 4GB 左右的内存。明明配置线程栈最大 256KB,为什么会出现 4GB 这么夸张的数字呢,到底哪里出了问题呢?

➜  ~ jcmd 24404 VM.native_memory summary
24404:
Native Memory Tracking:
Total: reserved=6635310KB, committed=5337110KB
-                 Java Heap (reserved=1048576KB, committed=1048576KB)(mmap: reserved=1048576KB, committed=1048576KB)
-                     Class (reserved=1066233KB, committed=15097KB)(classes #902)(malloc=9465KB #908)(mmap: reserved=1056768KB, committed=5632KB)
-                    Thread (reserved=4209797KB, committed=4209797KB)(thread #32)(stack: reserved=4209664KB, committed=4209664KB)(malloc=96KB #165)(arena=37KB #59)
-                      Code (reserved=249823KB, committed=2759KB)(malloc=223KB #730)(mmap: reserved=249600KB, committed=2536KB)
-                        GC (reserved=48700KB, committed=48700KB)(malloc=10384KB #135)(mmap: reserved=38316KB, committed=38316KB)
-                  Compiler (reserved=186KB, committed=186KB)(malloc=56KB #105)(arena=131KB #7)
-                  Internal (reserved=9693KB, committed=9693KB)(malloc=9661KB #2585)(mmap: reserved=32KB, committed=32KB)
-                    Symbol (reserved=2021KB, committed=2021KB)(malloc=1182KB #334)(arena=839KB #1)
-    Native Memory Tracking (reserved=85KB, committed=85KB)(malloc=5KB #53)(tracking overhead=80KB)
-               Arena Chunk (reserved=196KB, committed=196KB)(malloc=196KB)

重新以 VM.native_memory detail 参数运行 jcmd:

jcmd 24404 VM.native_memory detail

可以看到,有 16 个可疑线程,每一个线程保留了 262144KB 内存,也就是 256MB(通过下图红框可以看到,使用关键字 262144KB for Thread Stack from 搜索到了 16 个结果):

其实,ThreadStackSize 参数的单位是 KB,所以如果要设置线程栈 256KB,那么应该设置 256 而不是 256k。重新设置正确的参数后,使用 jcmd 再次验证下:

除了用于查看 NMT 外,jcmd 还有许多功能。可以通过 help,看到它的所有功能:

jcmd 24781 help

除了 jps、jinfo、jcmd、jstack、jstat、jconsole、jvisualvm 外,JDK 中还有一些工具,可以通过官方文档查看完整介绍。

官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/

 如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!


http://www.hkcw.cn/article/pSDnKgqoUm.shtml

相关文章

Java 大视界 -- 基于 Java 的大数据分布式文件系统在数字图书馆海量文献存储与管理中的应用优化(219)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也期待你毫无保留地分享独特见解,愿我们于此携手成长,共赴新程!💖 全网…

寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

文章目录 前言拓扑排序拓扑排序是怎么运作的拓扑排序的好处 强连通分量强连通是什么强连通分量是什么如何求 SCC 缩点 前言 更新的稍微有点晚…… 因为强连通分量这一块难学且知识点多&#xff0c;学习时间久了亿点&#xff0c;所以直到现在才更新。 拓扑排序 OI-Wiki 是这…

git下载和安装(完整版)

目录 一&#xff0c;官网下载 二, 安装步骤 1 双击直接安装【版本为64位系统的】 2 点击Next 3 点击Finish完成安装&#xff0c;验证安装&#xff0c;找一个桌面空白处&#xff0c;右键出现下列窗口 4 检验是否成功 一&#xff0c;官网下载 git官网地址&#xff1a;Gi…

系统思考:化繁为简的艺术

系统思考&#xff0c;其实是一门化繁为简的艺术。当我们能够把复杂的问题拆解成清晰的核心以及更加简单&#xff0c;从而提升团队的思考品质和行动品质&#xff0c;发挥最大的合力。 每个公司都想在某方面成为最优秀的&#xff0c;但是实际上具有穿透性的洞察力和摆脱虚荣心的清…

【Kotlin】简介变量类接口

【Kotlin】简介&变量&类&接口 【Kotlin】数字&字符串&数组&集合 文章目录 Kotlin_简介&变量&类&接口Kotlin的特性Kotlin优势创建Kotlin项目变量变量保存了指向对象的引用优先使用val来避免副作用 编译期常量后端变量Backing Fields后端属性…

8086 处理器 Flags 标志位全解析:CPU 的 “晴雨表” 与 “遥控器”总结:

引入&#xff1a; 你是否好奇&#xff0c;当 CPU 执行一条加法指令时&#xff0c;如何自动判断结果是否超出范围&#xff1f;当程序跳转时&#xff0c;如何快速决定走哪条分支&#xff1f;甚至在调试程序时&#xff0c;为何能让 CPU “一步一停”&#xff1f;这一切的答案&…

uniapp uni-id Error: Invalid password secret

common文件夹下uni-config-center文件夹下新建uni-id,新建config.json文件 复制粘贴以下代码&#xff0c;不要自己改&#xff0c;格式容易错 {"passwordSecret": [{"type": "hmac-sha256","version": 1}], "passwordStrength&qu…

从0到1上手Trae:开启AI编程新时代

摘要&#xff1a;字节跳动 2025 年 1 月 19 日发布的 Trae 是一款 AI 原生集成开发环境工具&#xff0c;3 月 3 日国内版推出。它具备 AI 问答、代码自动补全、基于 Agent 编程等功能&#xff0c;能自动化开发任务&#xff0c;实现端到端开发。核心功能包括智能代码生成与补全、…

云计算和服务器

一、云计算概述 ICT是世界电信协会在2001年的全球性会议上提出的综合性概念&#xff0c;ICT分为IT和CT&#xff0c;IT(information technology)信息技术&#xff0c;负责对数据生命周期的管理&#xff1b;CT(communication technology)&#xff0c;负责数据的传输管理。 CT技术…

云计算与分布式系统:从零开始构建!

🏆本文收录于「编程与技术实战」专栏,此专栏涵盖了C/C++编程、人工智能、数据结构、机器学习等技术领域的内容,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 本文目录: 前言云计算概念与架构什么是云计算?…

零基础入门haproxy七层代理

文章目录 haproxy的安装和服务信息global配置proxies配置defaults配置frontend配置backed配置listen配置 socat工具 haproxy算法静态算法动态算法其他算法 高级功能及配置案例基于cookie会话保持HAProxy状态页IP透传四层IP透传七层IP透传 ACL匹配规范基于HTTP请求头部的匹配精确…

清华大学杨诚最新Nature子刊

研究背景 电致变色&#xff08;Electrochromic, EC&#xff09;器件作为一种新兴的节能和调光技术&#xff0c;展示了动态调节光和热透射率的能力&#xff0c;是未来智能建筑、智能汽车天窗以及智能可穿戴设备的重要技术组成。然而&#xff0c;传统的EC器件的商业化面临着诸如…

【课程笔记】华为 HCIP-Cloud Computing 云计算08:OpenStack网络管理

OpenStack网络管理 目录 OpenStack网络管理 一、Linux网络虚拟化基础 二、Neutron简介 三、Neutron概念 四、Neutron架构 五、Neutron典型操作及流程 六、Neutron网络流量分析 一、Linux网络虚拟化基础 Linux下的网络虚拟化本质就是将原本物理网络中的网卡、物理虚拟机…

使用异步编程模型结合资源预测算法优化云计算环境下的任务调度与能耗管理技术详解

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用异步编程模型结合资源预测算法优化云计算环境下的任务调度与能耗管理技术详解 使用异步编程模型结合资源预测算法优化云计算…

云计算——云计算关键技术

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 一.云计算关键技术 1.虚拟化技术 2.分布式数据存储技术 &#xff08;1&…

2024广东省职业技能大赛云计算——私有云(OpenStack)平台搭建

OpenStack搭建 前言 搭建采用双节点安装&#xff0c;即controller控制节点和compute计算节点。 CentOS7 系统选择 2009 版本&#xff1a;CentOS-7-x86_64-DVD-2009.iso 可从阿里镜像站下载&#xff1a;https://mirrors.aliyun.com/centos/7/isos/x86_64/ OpenStack使用竞赛培…

云计算时代的运维: 职业发展方向与岗位选择

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

如何找到一条适合自己企业的发展之路?

一个创业型的企业&#xff0c;开始就需要面向市场&#xff0c;通过自己的服务或产品&#xff0c;帮助用户解决问题&#xff0c;为客户创造价值&#xff0c;通过为客户创造的价值&#xff0c;出创造一定的的现金流&#xff0c;让企业存活下来&#xff01; 企业的运营过程中&…

Github 热点 Github 热点 Syncthing:多台设备,持续同步文件,安全同步,隐私无忧!

今日推荐&#xff1a;syncthing Syncthing是一个开源、安全且易于使用的持续文件同步工具&#xff0c;可在多台计算机之间自动同步文件。 1prompt-eng-interactive-tutorial 今日星标 1211 总星标数 4273 主要语言 Jupyter Notebook https://github.com/anthropics/prompt-e…

K 值选对,准确率翻倍:KNN 算法调参的黄金法则

目录 一、背景介绍 二、KNN 算法原理 2.1 核心思想 2.2 距离度量方法 2.3 算法流程 2.4算法结构&#xff1a; 三、KNN 算法代码实现 3.1 基于 Scikit-learn 的简单实现 3.2 手动实现 KNN&#xff08;自定义代码&#xff09; 四、K 值选择与可视化分析 4.1 K 值对分类…