3

我正在开发一个项目,我需要在其中获取 Java 应用程序的本机堆栈。我能够部分地实现这一点。感谢 ptrace/multiprocessing 和信号。

在 Linux 上,普通的 java 应用程序至少有 14 个线程。在这 14 个中,我只对必须获取本机堆栈的主线程感兴趣。考虑到这个目标,我已经使用 fork() 启动了一个单独的进程,它正在监视主线程的本机堆栈。简而言之,我有 2 个单独的进程:一个正在被监控,另一个使用 ptrace 和信号处理进行监控。

监测过程中的步骤:

1) 从进程中的其他 14 个线程中获取主线程 ID。

2) ptrace_attach main_ID

3) ptrace_cont main_ID

连续循环开始

{

4)杀死(main_ID,SIGSTOP),

5) nanosleep 并从 /proc/[pid]/stat 目录检查状态

6) ptrace_peekdata 读取堆栈和导航

7) ptrace_cont main_ID

8) nanosleep 并从 /proc/[pid]/stat 目录检查状态

}

9) ptrace_detach main_ID

这完美地连续提供了本机堆栈信息。但有时我面临一个问题。

问题:

当我将 kill(main_ID, SIGSTOP) 发送到主线程时,进程中的其他线程进入完成或停止状态(T)并且整个进程阻塞。这不是一致性行为,整个过程正确执行。我无法理解这种行为,因为我只是在向主线程发出信号,为什么其他线程会受到影响?有人可以帮我分析问题吗?

我也尝试在进程的所有线程上执行 CONT 和 STOP 信号,但有时问题仍然存在。

谢谢,桑迪普

4

1 回答 1

0

假设您使用的是 Linux,您应该使用 tkill(2) 或 tgkill(2) 而不是 kill(2)。在 FreeBSD 上,您应该使用 SYS_thr_kill2 系统调用。根据 tkill(2) 联机帮助页:

tgkill() 将信号 sig 发送到线程组 tgid 中线程 ID 为 tid 的线程。(相比之下,kill(2) 只能用于向整个进程(即线程组)发送信号,并且该信号将被传递到该进程内的任意线程。)

忽略关于 tkill(2) 和朋友用于内部线程库使用的东西,它通常被调试器/跟踪器用于向特定线程发送信号。

此外,您应该使用 waitpid(2)(或它的一些变体)来等待线程接收 SIGSTOP,而不是轮询 /proc/[pid]/stat。这种方法将更有效,响应更快。

最后,您似乎正在执行某种堆栈采样。您可能需要查看Google PerfTools,因为这些工具包括一个 CPU 采样器,该采样器正在执行堆栈采样以获得对哪些函数消耗最多 CPU 时间的估计。您也许可以重用这些工具已经完成的工作,因为堆栈采样很难变得健壮。

于 2011-11-01T04:28:26.033 回答