如何用GDB获取地址信息及排查Java应用futex系统调用等待问题
别担心,我一步步带你搞定这个问题——用GDB追踪耗时futex对应的共享资源其实没那么复杂,哪怕你刚接触GDB也能跟着做:
准备工作
首先确保系统上安装了GDB(用apt install gdb或者yum install gdb就能搞定)。如果能用上带调试符号的JDK(比如安装openjdk-11-dbg这类包),分析起来会更顺畅,没有的话也能查到核心信息。
步骤1:获取Java进程的PID
先找到你的目标Java进程ID,用JDK自带的jps命令最方便:
jps -l
或者用ps命令筛选:
ps aux | grep java
记下输出里的PID(比如假设是12345)。
步骤2:用GDB附加到Java进程
打开终端,输入命令附加到目标进程:
gdb -p 12345
注意:附加进程时,Java进程会暂时暂停。如果是生产环境,你可以加参数让GDB附加后自动恢复进程运行:
gdb -p 12345 --ex "continue"
步骤3:设置futex系统调用断点
在GDB的交互提示符里,输入命令捕获所有futex系统调用:
catch syscall futex
然后让进程继续运行:
continue
步骤4:触发耗时futex并暂停分析
当你在strace里观察到那个耗时的futex等待时,GDB会自动触发断点,暂停进程。这时候我们需要查看futex的核心参数——共享内存地址(uaddr):
- 在x86_64架构下,futex的第一个参数(uaddr)存在
rdi寄存器里,输入命令查看:
输出的十六进制值就是futex等待的共享内存地址(比如p $rdi0x7f1234567890)。
步骤5:定位共享资源的归属
拿到地址后,我们来分析这个地址属于什么资源:
- 查看内存映射:输入命令查看进程的所有内存区域,找到地址对应的区间:
你能看到这个地址属于堆、匿名共享内存,还是某个共享库(比如JVM的libjvm.so)。info proc mappings - 查看地址附近的内存内容:用命令查看地址周围的内存结构,判断是不是锁相关的结构(比如pthread_mutex_t):
x/16xw 0x7f1234567890 # 替换成你拿到的地址 - 查看调用栈:输入命令查看当前线程的调用栈,结合Java线程栈定位到具体的代码逻辑:
如果是Java应用,你可以同时用btjstack 12345(替换成你的PID)查看Java线程栈,把GDB里的线程ID(用p $tid查看)和jstack里的线程对应起来,就能找到对应的锁对象或业务代码。
实用小技巧
- 如果只想捕获futex等待操作(而不是所有futex调用),可以给断点加条件:
catch syscall futex condition 1 $rsi == 0 # FUTEX_WAIT的操作码是0,不同架构可能有差异,可查man futex确认 - 如果你需要持续监控,断点触发后处理完输入
continue就能让进程继续运行,等待下一次触发。
内容的提问来源于stack exchange,提问作者Ratatouille
相关产品推荐
相关产品推荐

