当使用jmap,jstack是用-F参数的时候,是通过调用系统调用ptrace来取的寄存器的信息,关于linux下的ptrace实现可以参考我的博客(http://blog.csdn.net/raintungli/article/details/6563867)
在jdk6u23版本之前你会发现,当你使用jstack -F的时候 经常在logger 里面 看到错误信息,直接抛出异常,根本无法看到堆栈信息。
Thread 26724: (state = BLOCKED)
Error occurred during stack walking:
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: get_thread_regs failed for a lwp
at sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal$LinuxDebuggerLocalWorkerThread.execute(LinuxDebuggerLocal.java:152)
at sun.jvm.hotspot.debugger.....
通过查看源码,最后调用的函数是process_get_lwp_regs /ps_proc.c
static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct user_regs_struct *user) { // we have already attached to all thread 'pid's, just use ptrace call // to get regset now. Note that we don't cache regset upfront for processes. // Linux on x86 and sparc are different. On x86 ptrace(PTRACE_GETREGS, ...) // uses pointer from 4th argument and ignores 3rd argument. On sparc it uses // pointer from 3rd argument and ignores 4th argument #if defined(sparc) || defined(sparcv9) #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, addr, data) #else #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, data, addr) #endif #ifdef _LP64 #ifdef PTRACE_GETREGS64 #define PTRACE_GETREGS_REQ PTRACE_GETREGS64 #endif #else #if defined(PTRACE_GETREGS) || defined(PT_GETREGS) #define PTRACE_GETREGS_REQ PTRACE_GETREGS #endif #endif /* _LP64 */ #ifdef PTRACE_GETREGS_REQ if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) { print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid); return false; } return true; #else print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n"); return false; #endif }
通过源码,可以查到print_debug函数是通过环境变量LIBSAPROC_DEBUG来控制
设置
export LIBSAPROC_DEBUG=1
运行
jstack -F processid
我们能看到错误中多了一行
Thread 26724: (state = BLOCKED) libsaproc DEBUG: ptrace(PTRACE_GETREGS, ...) not supported
#ifdef _LP64 #ifdef PTRACE_GETREGS64 #define PTRACE_GETREGS_REQ PTRACE_GETREGS64 #endif #else #if defined(PTRACE_GETREGS) || defined(PT_GETREGS) #define PTRACE_GETREGS_REQ PTRACE_GETREGS #endif #endif /* _LP64 */
解决办法
a. 因为这是jvm 编译级别的bug,除非你重现修改编译libsaproc.so,覆盖目录/jdk1.6.0_23/jre/lib/amd64
笔者自己编译了这个lib,可以在csdn上下载(http://download.csdn.net/detail/raintungli/4065304),笔者编译的jdk版本是1.6.23 build(19.0)
b. 建议升级jvm到1.6.30版本,该版本已经测试过,已经修复该bug.
后话:
if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) { print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid); return false; }