V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dirtydeeds
V2EX  ›  Java

[求助]关于一个 jvm 崩溃的问题

  •  
  •   dirtydeeds · 14 天前 · 1331 次点击

    求助各位,实在找不到解决方案,不知道大家有没有遇到过类似的问题,

    问题描述

    我是在一个 arm 环境的 ubuntu 工控机上跑一个 springboot 些的 java 后端程序,会不时遇到 jvm 崩溃,而且多在调用接口的时候,hs_err_pid*.log 文件显示是在[libpthread.so.0+0x755c]start_thread+0xbc 这个位置, 分析 core dump 文件也是在这个位置崩溃的,

    可疑的诱因:我这个后端程序会调用一个第三方提供的 so 库文件连接局域网一个相机设备,当相机不在线时我的程序就会变得容易崩溃,但我单独使用同一个 jdk 写一个定时调用该 so 库测试的 demo 时候又没有崩溃的情况发生,不知道是不是我的后端程序有更多复杂业务的原因

    使用的 java 版本

    java version "17.0.10" 2024-01-16 LTS Java(TM) SE Runtime Environment (build 17.0.10+11-LTS-240) Java HotSpot(TM) 64-Bit Server VM (build 17.0.10+11-LTS-240, mixed mode, sharing)

    ubuntu 版本 20.04.5 LTS ,

    Linux linux 5.10.110 #2 SMP Mon May 6 16:55:18 CST 2024 aarch64 aarch64 aarch64 GNU/Linux

    gdb 分析 core dump 崩溃点的结果:

    (gdb) bt
    #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
    #1  0x0000007fa0695aac in __GI_abort () at abort.c:79
    #2  0x0000007f9ffafc38 in os::abort(bool, void*, void const*) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #3  0x0000007fa01a5f3c in VMError::report_and_die(int, char const*, char const*, std::__va_list, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)
        () from /userdata/hifi/jdk/lib/server/libjvm.so
    #4  0x0000007fa01a6908 in VMError::report_and_die(Thread*, unsigned int, unsigned char*, void*, void*, char const*, ...) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #5  <signal handler called>
    #6  0x0000007f9ff9b2f0 in os::is_first_C_frame(frame*) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #7  0x0000007fa01a0f34 in next_frame(frame, Thread*) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #8  0x0000007fa01a1fd8 in VMError::print_native_stack(outputStream*, frame, Thread*, char*, int) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #9  0x0000007fa01a3738 in VMError::report(outputStream*, bool) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #10 0x0000007fa01a5e30 in VMError::report_and_die(int, char const*, char const*, std::__va_list, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)
        () from /userdata/hifi/jdk/lib/server/libjvm.so
    #11 0x0000007fa01a6908 in VMError::report_and_die(Thread*, unsigned int, unsigned char*, void*, void*, char const*, ...) () from /userdata/hifi/jdk/lib/server/libjvm.so
    #12 0x0000007fa00623bc in JVM_handle_linux_signal () from /userdata/hifi/jdk/lib/server/libjvm.so
    #13 <signal handler called>
    #14 start_thread (arg=<error reading variable: Cannot access memory at address 0x4a28>) at pthread_create.c:478
    Backtrace stopped: Cannot access memory at address 0x49c8
    
    8 条回复    2024-05-21 20:08:15 +08:00
    cppc
        1
    cppc  
       13 天前
    没有找到稳定的复现方法还不好说,大概率是 JAVA 和 C 库共享内存的问题,小概率是 C 库自己的问题。
    letianqiu
        2
    letianqiu  
       13 天前 via Android
    看报错的位置是创建新线程的时候,spring boot 的 thread pool 是启动的时候创建的,应该和这个 crash 无关,可以查看一下 so 和业务代码里有没有开新线程
    oneisall8955
        3
    oneisall8955  
       13 天前 via Android
    第三方库是 aarch64 编译后的吗?
    leegoo
        4
    leegoo  
       13 天前   ❤️ 1
    之前我也遇到过 java 调用 c++ 偶发性导致程序崩溃

    我的排查过程是,通过增加 jvm 参数
    -XX:+CreateMinidumpOnCrash
    然后在崩溃的时候会产生 dump 日志,与常规崩溃日志(hs_err_pid*.log )不同的是,他会保留一份类似于 c++ 异常的堆栈以及入参数据

    然后开发 c++的工程师就拿着详细的信息,很快就定位到问题了(最终还是代码问题)
    leimu012
        5
    leimu012  
       13 天前
    我之前遇到过 java 调 so 文件就 jvm 崩溃,不过是在容器里才会发生,实体机和虚拟机里不会,我们当时分析是容器缺了部分 c 的环境,但是也不知道怎么排查缺的是什么
    dirtydeeds
        6
    dirtydeeds  
    OP
       13 天前
    感谢各位帮忙
    @cppc 发现自己对 jna 一点都不熟悉,我查查资料
    @oneisall8955 是的, 是 ararch64 编译后的
    @letianqiu so 代码对方不提供,也在和对方沟通,不过他们的 demo 跑不出问题就不是很配合
    @leegoo 感谢,我试试
    @leimu012 谢谢回复,原本这个项目是也是要放 x64 环境 docker 跑的,不过领导搞了个工控机让部署
    letianqiu
        7
    letianqiu  
       13 天前
    @dirtydeeds 你可以尝试一下让 spring boot 里调用该库的 method 不要被 JIT 。类似`-X:CompileCommand=exclude,the/package/and/Class,methodName`。然后看看是不是还是 crash 在同样的地方
    cppc
        8
    cppc  
       12 天前
    分享一点经验:

    ## C 风格字符串

    需要注意 C 风格字符串是靠 null-byte(0x0)标记字符串长度

    ## 结构体传参

    要注意是 ByReference 还是 ByValue ,核对 C 端的函数原型

    ## 结构体内存布局

    要注意对齐方式,仔细核对 C 端的结构体声明

    ## 结构体 memory dump

    开启 `-Djna.dump_memory=true`

    > Normally when you invoke toString on a Structure, it will print each defined field with its calculated memory offset. If when launching the VM, you pass it "-Djna.dump_memory=true", toString will also dump the contents of the corresponding native memory. This is useful to determine if you've added or omitted a field, or chosen an incorrect size. Viewing the memory as bytes usually makes it clear where field boundaries should be, assuming the memory has been initialized by native code.

    ## 日志

    对 C 端的函数调用做一下封装,调用前后记录日志,先把崩溃的位置找到
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3792 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 10:20 · PVG 18:20 · LAX 03:20 · JFK 06:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.