Java 进程 hang 住了, 怎么拿到 heap dump? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
manecocomph
V2EX    Java

Java 进程 hang 住了, 怎么拿到 heap dump?

  •  
  •   manecocomph 2021-02-05 13:29:47 +08:00 2438 次点击
    这是一个创建于 1709 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原文格式稍好 , 欢迎评论讨论, 讨论能学到更多知识.

    原文链接: https://mp.weixin.qq.com/s/7SHlfonUEW8oWx_IAjuYRw

    常诊断 Java 问题, 做 heap dump 是常规项目, 因为 heap dump 就像一个宝藏一样, 里面是运行时的各种真实状态. 一般使用 JDK 提供的命令行工具或者使用封装好的特定编程接口, 很容易做出一个 heap dump. 但是如果遇到 JVM 已经不响应了, 如何才能做出一个 heap dump 呢?

    场景重现

    看到线上有个应用 CPU 使用率达到 100%, 不响应任何请求, 进一步检查发现是 GC 导致的, GC overhead 已经达到 100%. 这个时候, 为了发现内存堆积的真正原因, 需要做一个 heap dump.

    首先尝试使用应用框架提供的 Restful API 的形式去做 heap dump, 可是等了 10 秒后还没响应. 这是因为: 内存已经不够用, 但是之前进来的请求还没完成, 各个线程都在等待内存给自己用, 可是内存却不能释放出来. 形成一个矛盾体: 应用线程等空闲内存继续运行, 却没有内存, 只能暂停, GC 线程拼命做 Full GC, 可是没有太多内存可以释放, 只能一遍一遍做.

    Hotspot JVM 对于这种情况的默认处理是: 如果连续 5 次 Full GC, 每次 GC overhead 都超过 98%, 回收的空闲内存不足 2%, 就抛出 OOM. 不满足任何一个条件, 比如有次回收多于 2%, 就不会抛出 OOM.

    这个时候, 由于所有应用线程都完成不了现有的任务, 所以无法承接新的请求, 导致不响应任何新请求.

    JDK 提供的命令行 jcmd | jmap

    早期 JDK 提供了 jmap 命令行工具, 后续的 JDK 又提供了 jcmd 命令行工具, 都可以帮助我们方便的去做 heap dump. 于是, 我们转而使用 jcmd 去尝试获得 heap dump.

    然而, 这次又失败了: 无法 attach 到目标进程:

    /usr/bin/jcmd 7674 GC.heap_dump /tmp/heap.log.hprof 7674: com.sun.tools.attach.AttachNotSupportedException:Unable to open socket file:target process not responding or HotSpot VM not loaded at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106) at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63) at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:213) at sun.tools.jcmd.JCmd.executeCommandForPid(JCmd.java:140) at sun.tools.jcmd.JCmd.main(JCmd.java:129)

    偶尔情况下, 如果我们多试几次, 有可能某次正好碰到 GC 线程释放出部分内存, 让 JVM 可以响应我们的请求. 这种概率非常小.

    那么有没有其它比较靠谱的办法呢?

    Core dump 转 heap dump

    core dump 是操作系统进程的瞬时的 snapshot. 我们可以先做一个 core dump, 然后通过 core dump 转 heap dump 的方式, 获得我们期望的 heap dump. 详细步骤如下:

    1. 首先 安装 gcore $ sudo apt install gdb -y #gcore command in gdb package

    2. 把 core size limit 改为 unlimited $ sudo cp /etc/security/limits.conf /etc/security/limits.d/ # 复制 limits.conf 模板文件到配置文件夹 $ sudo vim /etc/security/limits.d/limits.conf # 编辑配置文件, 修改我们目标 Java 进程的用户的配置 appUser hard core unlimited appUser soft core unlimited

    3. 获取 core dump

      $ pgrep java # 显示查看目标进程的 pid $ sudo gcore <pid>
      $ ls -lah core.<pid> # 查看获取的 core dump 的大小, 通常在当前目录

    4. 把 core file 的 hard, soft 修改的配置改回来 $ sudo rm -f /etc/security/limits.d/limits.conf # 之前我们把模板加到这个文件, 现在删掉

    5. 转换 core dump 到 Java heap dump. 一定要使用运行对应目标进程运行的 JDK.

      $ find /app -name jmap # 找到运行目标进程的 JDK 里面的 jmap 命令 $ sudo /usr/bin/jmap -dump:format=b,file=heap.hprof /usr/bin/java ./core.<pid> #转换

    6. 等使用完之后, 清理 dump 文件(因为 dump 文件比较占磁盘)

      $ rm core.<pid> dump.hprof

    至此, 我们终于有了这个 heap dump 宝藏, 剩下的就是去宝藏里面查找我们需要的信息了(后续将会介绍如何使用 mat 有效的分析 heap dump).

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3688 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 10:20 PVG 18:20 LAX 03:20 JFK 06:20
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86