首页 > 其他分享 >jmap执行失败了,怎么获取heapdump?

jmap执行失败了,怎么获取heapdump?

时间:2023-04-16 14:15:00浏览次数:49  
标签:core 文件 coredump 获取 heapdump 内存 jvm jmap

原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明。

在之前的OOM问题复盘中,我们添加了jmap脚本来自动dump内存现场,方便排查OOM问题。

但当我反复模拟OOM场景测试时,发现jmap有时可以dump成功,有时会报错,如下:
jmap_failed
经过网上一顿搜索,发现两种原因可能导致这个问题,一是执行jmap用户与jvm进程用户不一致,二是/tmp/.java_pidXXX文件被删除,但经过检查,这都不是我们jmap失败的原因。

经过了解,jmap导出内存的原理,大致如下:
jmap

  1. 如果jvm进程id是8255,jmap会先创建一个/tmp/.java_pid8255文件,然后发送SIGQUIT信号给jvm。
  2. jvm收到信号后启动AttachListener线程,以UNIX domain socket的形式监听/tmp/.java_pid8255文件,以接收命令。
  3. jmap也以UNIX domain socket的形式连接上/tmp/.java_pid8255文件,并发送dumpheap命令给jvm,这个过程中jvm会检查命令发送方用户的euid/egid是否与自己一致。
  4. AttachListener线程收到dumpheap命令后,等到JVM进入Safepoint后,执行HeapDumper操作以导出heap.hprof文件。

可以看出,当jvm已经卡死,或有长时间的GC正在Safepoint中执行,都会导致jmap长时间读不到命令的响应而超时失败!

使用jmap -F

当给jmap添加-F参数时,jmap会使用Linux的ptrace机制来导出堆内存,ptrace是Linux平台的一种调试机制,像strace、gdb都是基于它开发的,它使得调试进程(jmap)可以直接读取被调试进程(jvm)的原生内存,然后jmap再根据jvm的内存布局规范,将原生内存转换为hprof格式。

但在实际执行时,会发现jmap -F执行得非常慢,可能要几个小时,这是因为ptrace每次只能读一个字的内存,而我们的堆有10G,因此jmap -F对于我们几乎无法使用。

注:这里说的原生程序,指的是类似于C/C++这种直接编译出来、不需要依赖语言虚拟机的程序,而原生内存,指的是通过malloc或mmap等直接申请出来的内存。

使用gcore

有过Linux下原生程序调试经验的,应该会知道gcore这个实用工具,它可用来生成程序原生内存的core文件,然后jstack、jmap等都可以读取此类文件,如下:

# 生成core文件,8787是进程号
$ gcore -o core 8787
Saved corefile core.8787
[Inferior 1 (process 8787) detached]

$ ll -lh core.8787
-rw-r--r-- 1 work work 5.8G 2023-04-16 11:40:00 core.8787

# 从core文件中读取线程栈
$ jstack `which java` core.8787

# 将core文件转换为hprof文件,很慢,建议摘流量后执行
$ jmap -dump:format=b,file=heap.hprof `which java` core.8787

但是当我使用jmap转换core文件时,我发现我本机测试时可以成功,但在测试服务器上却一直报错,如下:
core_to_hprof_fail
我网上找了好久,都没找到报此错误的原因...

但我发现gcore执行时,是有一些警告信息的,如下:
gcore_warn
看起来可能是gcore导出的core文件不全,联想到jvm部署在容器中,怀疑是有某些权限限制,导致部分程序内存导出失败了。

使用Linux内核的coredump机制

除了gcore可以导原生内存,其实Linux内核也有自动的coredump机制,即进程在收到某些信号后,会自动触发内核的coredump机制,内核会负责将进程的原生内存保存为core文件,而内核一般是最高权限运行的,所以它生成的core文件应该是完整的。

先开启coredump机制,如下:

# 检查是否开启,输出unlimited表示core文件不受限制,即完全开启
$ ulimit -c

# 临时开启coredump
$ ulimit -c unlimited

# 永久开启
$ echo "ulimit -c unlimited" >> /etc/profile

然后,配置一下coredump文件保存位置,如下:

# 查看当前配置
$ cat /proc/sys/kernel/core_pattern
/home/core/core.%e.%p.%t

# 配置coredump文件保存位置,并使其生效
$ vi /etc/sysctl.conf
kernel.core_pattern=/home/core/core.%e.%p.%t
$ sysctl –p /etc/sysctl.conf

core_pattern占位符解释

占位符 解释
%p pid
%u uid
%g gid
%s signal number
%t UNIX time of dump
%h hostname
%e executable filename

注:如果没有权限修改core_pattern路径,可考虑使用软链接ln -s做路径跳转,当然,还需要保证coredump路径有写入权限。

配置ok后,可通过kill发送信号来触发内核coredump,可触发coredump的常见信号如下:

  • SIGQUIT 数值2 从键盘输入Ctrl+'\'可以产生此信号
  • SIGILL 数值4 非法指令
  • SIGABRT 数值6 abort调用
  • SIGSEGV 数值11 非法内存访问
  • SIGTRAP 数值5 调试程序时使用的断点

我选择了SIGABRT信号,即kill -6,经过验证,可生成core文件,而且core文件也能被jmap转换为hprof文件。

有了hprof文件,就可以愉快地使用MAT、JVisualVM、JMC等工具进行内存分析啦

标签:core,文件,coredump,获取,heapdump,内存,jvm,jmap
From: https://www.cnblogs.com/codelogs/p/17323197.html

相关文章

  • webFlux 获取上传文件的附带参数
    前端上传文件uploadFilePromise(url){returnnewPromise((resolve,reject)=>{leta=uni.uploadFile({url:base.baseUrl+uploadHemogram.concat(this.patient.name),//仅为示例,非真实的接口地址......
  • 2023【xm格式转不了mp3】教你正确下载喜马拉雅mp3,并优雅获取音频!
    喜马拉雅Windows和Mac客户端下载缓存的音频是xm格式,而且限制只可使用该喜马拉雅软件才能打开,而且经过加密的,因此对于电脑小白来说就不要想着解密xm格式的文件了,而且网上基本没有xm转mp3/m4a的工具。 这次分享的不是如何将xm格式转换成mp3的工具,而是采用了跳过xm格式。直接下载......
  • 【原创】SQLSERVER 通过 newsequentialid() 获取有序Guid 的注意事项
    SQLSERVER2005版本开始,支持获取有序Guid,函数为:newsequentialid(),使用该函数注意事项:1、表存在对应类型:uniqueidentifier,可以设置default 为:newsequentialid() 来自动生成有序Guid2、字段类型为:uniqueidentifier时,值只能是36位有效格式的字符串,不能为其他格式或空的字符串,而......
  • 《Python算法交易实战》——yfinace获取yahoo财经数据
    因为从2021年11月1日起,用户无法从中国大陆地区使用Yahoo产品与服务所以下面两个错误,都是代理配置的问题error:Notimezonefound,symbolmaybedelistederror:Nodatafoundforthisdaterange,symbolmaybedelisted以下是解决办法:1.实现强劲上网,保证你可以在浏览器......
  • springboot打成jar包resources下文件的获取
    importorg.apache.poi.util.IOUtils;importorg.springframework.boot.system.ApplicationHome;importorg.springframework.core.io.ClassPathResource;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream......
  • 一统天下 flutter - UI: MediaQuery - 获取屏幕的相关信息,使系统设置中的字体大小无效
    一统天下flutterhttps://github.com/webabcd/flutter_demo作者webabcd一统天下flutter-UI:MediaQuery-获取屏幕的相关信息,使系统设置中的字体大小无效示例如下:lib\ui\media_query.dart/**MediaQuery-获取屏幕的相关信息,使系统设置中的字体大小无效*/imp......
  • vue通过Export2Excel.js进行导入excel,获取数据
    <!--封装的模板下载和导入按钮和功能组件--><template><spanstyle="margin-left:10px"><el-buttonsize="mini"class="el-icon-download"@click="downFiles">下载模板</el-button><el-upload......
  • mongodb 获取集合所有记录中曾出现过的字段
    switchtothedbyou'reusingandtype:mr=db.runCommand({"mapreduce":"myCollectionName","map":function(){for(varkeyinthis){emit(key,null);}},"reduce":function(key,stuff){ret......
  • 登录获取验证号倒计时操作
    //这里是一整个验证码框,验证码图标加输入框加获取验证码(显示倒计时框)<viewclass="rowbetweend-items-centerb-b"><viewclass="iconfonticon-suo"style="color:#FFFFFF;margin:020upx;"></view><inputtype="number"......
  • MFC-GetWindowRect获取指定窗口或控件的边框矩形的尺寸
     HWNDhDlgWnd=::FindWindow(_T("#32770"),_T("测试窗口"));if(hDlgWnd){::ShowWindow(hDlgWnd,SW_NORMAL);::SetForegroundWindow(hDlgWnd);HWNDhBtn=::GetDlgItem(hDlgWnd,0x3E8);CRectmRect;......