当前位置: 首页 > 工具软件 > Live Magic > 使用案例 >

jhat(Unrecognized magic number: 170..) jproflier(the selected snapshot does not have a valid..)

苏宜人
2023-12-01

环境

centos7 + java8 + tomcat8

分析dump文件

通过配置jvm的:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/xxx/xxx.dump

或者通过jmap -dump:live,format=b,file=xxx.dump命令生成dump文件

生成的dump文件比较大,所以在服务器上,通过tar -czvf error.dump.gz error.dump压缩dump文件,并拉取到本地(通过sz命令将压缩文件发送到本地,然后通过winrar解压)。之后通过jhat或者jprofiler(推荐)分析内存镜像。

dump解析问题

        1. 通过jprofiler分析,将error.dump后缀改为hprof,报错提示:the selected snapshot does not have a valid format

        2. 通过jhat error.dump,报错提示:Unrecognized magic number: 1701999215

PS C:\Users\Public\Desktop> jhat.exe C:\Users\zhufeifei\Desktop\error.dump
Reading from C:\Users\zhufeifei\Desktop\error.dump...
java.io.IOException: Unrecognized magic number: 1701999215
        at com.sun.tools.hat.internal.parser.Reader.readFile(Reader.java:94)
        at com.sun.tools.hat.Main.main(Main.java:159)

出现上述问题的原因是dump文件头信息不对,正常生成的dump文件头以0x4a415641 开头,所以分析工具在执行解析时会首先解析文件头是否为合法文件,如果不合法则出现上出问题。

处理方式1:

       将压缩文件名xxx.dump.gz更改为,xxx.dump.tar.gz,注意:最重要的时后缀tar.gz,决定能否在winrar上正确的进行解压和解包操作。原因见最后思考总结

处理方式2:

        查看dump文件的16进制形式,来确定头是否是0x4a415641开始

        查看方式:(git bash命令行, dump文件较大,不推荐使用可视化编辑工具)

$ xxd error.dump | head -35
00000000: 6572 726f 722e 646d 7000 0000 0000 0000  error.dmp.......
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 3030 3030 3630 3000 3030 3030  ....0000600.0000
00000070: 3030 3000 3030 3030 3030 3000 3335 3430  000.0000000.3540
00000080: 3137 3131 3735 3000 3134 3130 3031 3534  1711750.14100154
00000090: 3237 3100 3031 3134 3232 0020 3000 0000  271.011422. 0...
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000100: 0075 7374 6172 2020 0072 6f6f 7400 0000  .ustar  .root...
00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000120: 0000 0000 0000 0000 0072 6f6f 7400 0000  .........root...
00000130: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000200: 4a41 5641 2050 524f 4649 4c45 2031 2e30  JAVA PROFILE 1.0
00000210: 2e32 0000 0000 0800 0001 7aeb 4e36 8801  .2........z.N6..
00000220: 0000 0000 0000 0078 0000 7f41 47f3 1170  .......x...AG..p

可以发现此文件头并不是0x4a415641, 而真正的文件头在00000200处开始,因此只要将200偏移量之前的数据删除即可,左侧的为地址偏移量,16进制表示形式,首先要转换为10进制。

$ printf %d 0x200
512

二进制文件截取,跳过512个字节

$ dd if=error.dump of=head.dump bs=1k count=1 skip=512 iflag=skip_bytes
1+0 records in
1+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 0.0011282 s, 908 kB/s

查看 最终生成的文件头信息,可以看到文件头为0x4a415641开始

$ xxd error.dmp | head
00000000: 4a41 5641 2050 524f 4649 4c45 2031 2e30  JAVA PROFILE 1.0
00000010: 2e32 0000 0000 0800 0001 7aeb 4e36 8801  .2........z.N6..
00000020: 0000 0000 0000 0078 0000 7f41 47f3 1170  .......x...AG..p
00000030: 284c 6a61 7661 2f6c 616e 672f 5374 7269  (Ljava/lang/Stri
00000040: 6e67 3b4c 6a61 7661 2f75 7469 6c2f 5365  ng;Ljava/util/Se
00000050: 743c 4c6a 6176 612f 6c61 6e67 2f53 7472  t<Ljava/lang/Str

此后可以通过jhat或者jprofiler解析内存快照了。

思考&总结 

        上述问题只出现在window机器上解压后,格式不正确,在linux上通过tar -xvf解压得到的文件头是正常的。

        经过测试,发现出现此问题的原因是在服务器上通过命令: tar -czvf error.dump.gz error.dump,生成的压缩文件为error.dump.gz,到window上通过winrar解压出的文件头部无故多了文件名和文件属性信息,导致dump文件无法解析。

        解决方式:tar -czvf error.dump.tar.gz error.dump, 压缩文件名更改为xxx.tar.gz,在window上解压就没有问题了。由于tar是压缩和打包,所以仅命名为gz后缀时,winrar只进行解压并不会进行解包操作,导致附属在源文件头部的打包信息没有被正确的读取移除掉。

参考:stackoverflow

 类似资料:

相关阅读

相关文章

相关问答