我正在开发一个项目,我需要获得Java应用程序的本机堆栈。我能够部分实现这一目标。感谢ptrace / multiprocessing和信号。
在Linux上普通的java应用程序至少有14个线程。在这14个我感兴趣的只有主要线程,我必须得到本机堆栈。考虑到这个目标,我已经使用fork()启动了一个单独的进程,它监视主线程的本机堆栈。简而言之,我有两个独立的过程:一个是受监控的,另一个是使用ptrace和信号处理进行监控。
监控过程中的步骤:
1)从进程的其他14个线程中获取主线程id。
2)ptrace_attach main_ID
3)ptrace_cont main_ID
连续循环启动
{
4)kill(main_ID,SIGSTOP),
5)纳米睡眠并检查来自/ proc / [pid] / stat目录的状态
6)ptrace_peekdata读取堆栈并导航
7)ptrace_cont main_ID
8)纳米睡眠并检查来自/ proc / [pid] / stat目录的状态
}
9)ptrace_detach main_ID
这完美地提供了本机堆栈信息。但有时候我会面临一个问题。
问题:
当我向主线程发送kill(main_ID,SIGSTOP)时,来自进程的其他线程进入完成或停止状态(T)并且整个进程阻塞。这不是一致性行为,整个过程正确执行。我无法理解这种行为,因为我只是发信号主线程,为什么其他线程会受到影响呢? 有人可以帮助我分析问题吗?
我也尝试在进程的所有线程上执行CONT和STOP信号,但有时仍会出现问题。
谢谢,Sandeep
答案 0 :(得分:0)
假设您使用的是Linux,那么您应该使用tkill(2)或tgkill(2)而不是kill(2)。在FreeBSD上,你应该使用SYS_thr_kill2系统调用。根据tkill(2)手册页:
tgkill()将信号sig发送到线程ID为tid的线程 线程组tgid。 (相比之下,kill(2)只能用于发送 作为整体的进程(即线程组)的信号和信号 将被传递到该过程中的任意线程。)
忽略关于tkill(2)的内容和朋友正在使用内部线程库,调试器/跟踪器通常使用它来向特定线程发送信号。
此外,你应该使用waitpid(2)(或它的一些变体)来等待线程接收SIGSTOP而不是轮询/ proc / [pid] / stat。这种方法将更有效,更具响应性。
最后,您似乎正在进行某种堆栈采样。您可能需要查看Google PerfTools,因为这些工具包括正在进行堆栈采样的CPU采样器,以获取消耗最多CPU时间的函数的估计值。您可以重用这些工具已经完成的工作,因为堆栈采样可能很难实现。