还在靠重启解决性能问题?这些 JVM 神器你再不用,年终奖可就飞走了!

举报
喵手 发表于 2025/12/08 20:30:16 2025/12/08
【摘要】 开篇语哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,...

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

0. 前言:谁还没被性能问题折磨过?

性能问题,对于咱们程序员来说,简直就是“魔鬼的考验”。👹 表面上看,程序运行得好好的,但一旦遇到高并发、大数据量,立马就“原形毕露”。系统响应慢、CPU 居高不下、内存飙升、莫名其妙的线程阻塞……这些都是咱们加班的元凶!

更气人的是,这种 Bug 往往在开发环境根本测不出来,只有在生产环境,在用户眼皮底下,才跳出来给你一个“惊喜”!🤡

所以,掌握性能分析工具,就如同医生掌握了诊断病症的仪器。你不能光靠经验拍脑袋,你得有数据,有证据!

今天,我就带大家领略一下 jstack、jmap、jstat、async-profiler 的魅力。这可不是简单的命令行教程,咱们要结合实际场景,看看它们到底能帮你解决什么鬼畜问题!👻


1. jstack:死锁?线程卡死?它就是你的“线程抓捕专家”!

jstack,全称 Java Stack Trace,顾名思义,它主要用来打印 JVM 进程中所有线程的栈轨迹(stack trace)

它的作用就像什么呢? 就像你在公司年会玩“定格游戏”,突然主持人喊“Freeze!”所有人都得停下来,保持那一瞬间的动作。jstack 就是那个主持人,它能让你看到 JVM 中每个线程在某一瞬间都在干啥。🧘‍♀️

💡 场景:解决线程阻塞、死锁、CPU 飙高问题

  • 线程阻塞: 某个线程卡在某个方法调用上,或者等待某个锁,导致整个请求响应慢。
  • 死锁: 两个或多个线程互相持有对方所需的资源,谁也无法继续执行,永久阻塞。
  • CPU 飙高: 某个线程陷入了死循环,或者在执行大量计算,导致 CPU 负载过高。

🛠️ 实战操作

  1. 找到你的 Java 进程 ID (PID):

    ps -ef | grep java
    # 或者
    jps -l
    

    假设你的 PID 是 12345

  2. 生成线程堆栈:

    jstack 12345 > jstack.log
    

    注意: 建议多采集几次,每次间隔几秒,比如三次:

    jstack 12345 > jstack1.log
    sleep 5
    jstack 12345 > jstack2.log
    sleep 5
    jstack 12345 > jstack3.log
    

    这样做的目的是,如果某个线程只是偶尔卡顿,或者在等待资源,通过多次采样就能看出它的“轨迹”。如果是死循环或者死锁,那么在多次采样中它都会停留在同一个地方。

🔍 如何分析 jstack.log

  • BLOCKEDWAITINGTIMED_WAITING 状态: 这些状态说明线程在等待。

    • BLOCKED (on object monitor):线程正在等待获取一个对象锁。
    • WAITING (on object monitor):线程调用了 Object.wait()LockSupport.park() 等方法,正在等待被唤醒。
    • TIMED_WAITING:类似 WAITING,但有超时时间。
  • 寻找 deadlock jstack 会自动帮你检测死锁并高亮出来!这简直是福尔摩斯本人!✨

  • CPU 占用高的线程: 结合 top -Hp <PID> 命令,找到 CPU 最高的线程 ID,然后将该线程 ID 转换为 16 进制,在 jstack 文件中搜索。你就能看到这个“捣蛋鬼”正在执行哪个方法!

小结: jstack 就是你的“透视眼”,能一眼看穿线程在干嘛。当程序卡顿,没有响应时,首先想到的就是它!


2. jmap:内存泄漏?堆溢出?它就是你的“内存 X光机”!

jmap,全称 Java Memory Map。它主要用来生成 JVM 堆内存的快照(Heap Dump),分析内存中的对象情况。

它的作用就像什么呢? 就像你拍了一张照片,把内存里所有的对象、它们之间互相引用关系都“定格”下来。然后你可以用专业的工具(如 Eclipse MAT 或 JProfiler)来分析这张照片。📸

💡 场景:解决内存泄漏、OOM、GC 频繁问题

  • 内存泄漏 (Memory Leak): 对象创建后不再使用,但由于被某些引用链条“活生生”地拽着,GC 无法回收,导致内存不断上涨。
  • OOM (OutOfMemoryError): 内存不足,程序崩溃。
  • GC 频繁: 由于内存占用过高或分配不合理,导致 GC 频繁执行,系统卡顿。

🛠️ 实战操作

  1. 找到你的 Java 进程 ID (PID): (同 jstack)

  2. 生成堆内存快照:

    jmap -dump:format=b,file=heap.hprof 12345
    
    • format=b:指定输出格式为二进制,这是标准的堆转储文件格式。
    • file=heap.hprof:指定输出文件名。

    注意: 生成堆转储文件时,JVM 会暂停(STW),尤其是在堆内存很大的情况下,可能会暂停几十秒甚至几分钟!所以,在生产环境谨慎操作,最好选择业务低峰期。

  3. 分析堆转储文件:
    heap.hprof 文件下载到本地,用 Eclipse Memory Analyzer Tool (MAT) 或者 JProfiler 打开。

    • MAT 可以帮你找到最大的对象、哪个对象占用内存最多、哪个对象是 GC Root 等等。它还有强大的“Path To GC Roots”功能,能帮你分析为什么某个对象没有被回收。这简直就是你的“内存侦探”!🔍

小结: jmap 帮你把内存挖出来,让你看到所有对象的真实面貌和关系网。是解决内存问题的终极武器!


3. jstat:GC 监控?类加载?它就是你的“JVM 仪表盘”!

jstat,全称 JVM Statistics Monitoring Tool。它是一个非常轻量级的命令行工具,用来实时监控 JVM 各种运行状态信息,包括类加载、GC 行为、JIT 编译等。

它的作用就像什么呢? 就像汽车的仪表盘!🚗 你可以实时看到油耗(GC 频率)、发动机转速(类加载)、车速(JIT 编译)等各种参数,而不会对汽车本身造成任何负担。

💡 场景:定位 GC 性能瓶颈、内存区域使用情况

  • GC 频繁或耗时过长: 导致系统卡顿。
  • 内存区域(新生代、老年代)分配不合理: 导致内存利用率低或 GC 压力大。
  • Full GC 频繁: 这通常是老年代内存不足的信号。

🛠️ 实战操作

  1. 找到你的 Java 进程 ID (PID): (同 jstack)

  2. 实时监控 GC 情况:

    jstat -gcutil 12345 1000 10
    
    • -gcutil:显示 GC 统计信息(推荐,最常用)。
    • 12345:进程 ID。
    • 1000:每隔 1000 毫秒(1秒)刷新一次。
    • 10:总共刷新 10 次。

    输出示例:

      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
     0.00   0.00  12.56  90.23   98.76  96.54     10    0.123    1      0.045    0.168
     0.00   0.00  20.34  90.23   98.76  96.54     10    0.123    1      0.045    0.168
     ...
    

    关键字段:

    • E:Eden 区使用百分比。
    • O:Old 区(老年代)使用百分比。
    • YGC:Young GC 次数。
    • YGCT:Young GC 总耗时。
    • FGC:Full GC 次数。
    • FGCT:Full GC 总耗时。
    • GCT:所有 GC 总耗时。
  3. 监控堆内存:

    jstat -gc 12345 1000 10
    
    • -gc:显示堆内存使用情况(KBytes)。

小结: jstat 是你的“雷达”,能够实时发现 GC 和内存使用的异常。当你怀疑是 GC 导致卡顿,或者内存分配不合理时,jstat 是第一手资料的来源。


4. async-profiler:谁在偷偷吃我的 CPU?它就是你的“性能外科医生”!

async-profiler 是这四个工具里的“新星”和“黑科技”!⭐ 它是一个低开销的、能采样的、非侵入式的 JVM 性能分析工具。它能够以非常低的开销(通常低于 1%)生成 CPU 火焰图、内存火焰图、锁火焰图等,帮助你快速定位热点代码。

它的作用就像什么呢? 就像一个专业的“性能外科医生”,它能精准地切割出你的程序里最消耗 CPU、内存或者 I/O 的那块“病灶”,并用火焰图 (Flame Graph) 的形式直观地展现出来。🔥

💡 场景:定位 CPU 瓶颈、热点方法、I/O 阻塞、内存分配热点

  • CPU 占用过高: 找出哪个方法、哪行代码导致了 CPU 狂飙。
  • 方法调用链分析: 哪个函数调用了哪个函数,最终导致了性能问题。
  • GC 频繁: 找到频繁创建对象的“罪魁祸首”。
  • I/O 阻塞: 分析网络 I/O、磁盘 I/O 等待耗时。

🛠️ 实战操作

  1. 下载 async-profiler:

    # 例如:
    git clone https://github.com/jvm-profiling-tools/async-profiler.git
    cd async-profiler
    make # 编译
    
  2. 启动你的 Java 应用,并附加 async-profiler (或直接在运行时启动):

    # 方式一:在 JVM 启动参数中添加
    java -agentpath:/path/to/async-profiler/build/libasyncProfiler.so=start,file=cpu.svg,event=cpu,interval=9ms,duration=30s -jar your_app.jar
    
    # 方式二:在运行时动态 attach (推荐,无需重启应用)
    # 首先找到 PID
    # 然后运行:
    ./profiler.sh -d 30 -f cpu.svg 12345
    # -d 30: 采样 30 秒
    # -f cpu.svg: 输出到 cpu.svg 文件 (会生成火焰图)
    # 12345: 进程 ID
    
  3. 分析火焰图 cpu.svg
    用浏览器打开 cpu.svg 文件。

    • 宽度代表耗时占比: 越宽的“火焰”,说明该方法或方法栈占用 CPU 时间越多。
    • 高度代表调用栈深度: 堆栈的每一层表示一个方法。
    • 顶部是“最热”方法: 顶部最宽的火焰,通常就是需要优化的目标。

小结: async-profiler 及其生成的火焰图,是当前最先进、最直观的性能瓶颈分析工具。它能让你从宏观到微观,一览无余地看清程序的性能热点。简直是神器中的神器! 💯

5. 写在最后:工欲善其事,必先利其器!

看到没?这四个工具,各有神通,互相配合,简直就是一套性能分析的“天团组合”!🎤

  • jstat 帮你宏观监控,快速发现问题在哪里发生(GC?内存?)。
  • jstack 帮你微观定位,发现是哪个线程在“磨洋工”(死锁?阻塞?)。
  • jmap 帮你深层挖掘,找出是哪个对象在“吸血”(内存泄漏?OOM?)。
  • async-profiler 更是直接“手起刀落”,帮你精准找到性能热点和代码瓶颈!

所以啊,兄弟们,别再做那个只会敲 Ctrl+CCtrl+V 的“CRUD 仔”了!💪 把这些工具玩溜,你就是团队里那个能“力挽狂澜”、拯救生产环境于水火之中的**“性能英雄”**!🦸‍♂️

下次再遇到性能问题,请记住我的话:“别慌,打开终端,jstack 走起!” 你会发现,解决性能问题,其实也挺上头的!😎

好了,今天就聊到这儿。拿起你的键盘,赶紧找个跑着的 Java 应用,实战一下这些命令吧!实践出真知!✨

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。