生产环境或多或少会遇到CPU占用高或卡死的PHP进程。怎么才能知道这个进程此时在做什么呢?一种方法是strace跟踪系统调用和参数,这样可以大致知道PHP进程在做什么。要查看特定的PHP函数,您需要使用PHP扩展(xdebug、xhprof)或使用GDB进行调试。对于进阶点,还可以使用DTrace。我上周发现了ruby??-stacktrace。它直接读取ruby进程的内存获取堆栈信息,没有使用GDB和扩展,所以性能非常好,所以我也写了一个php-stacktrace,勉强能用的玩具。使用简单,只需下载并解压:$./php-stacktrace--helpphp-stacktrace0.1PHP程序的采样分析器USAGE:php-stacktraceFLAGS:-h,--help打印帮助information-V,--version打印版本信息ARGS:traceortoporoneshot到phpdebuginfo的路径您要分析的PHP进程的PID所有三个参数都是必需的。COMMAND可以是trace、top、oneshot。Oneshot只检查一次然后退出。Trace和top会一直跟踪。trace的输出可用于生成火焰图。top统计函数需要时间。DEBUGINFO是调试信息文件的路径。Linux通常需要单独安装debuginfo包,因为路径不会从elf中解析出来,所以必须通过这个参数指定。通常的路径是/usr/lib/debug/.dwz/php...。(在隐藏目录下,算是个小坑)。PID就是要跟踪的PHP进程ID。顺便说一句,仅支持非线程安全的PHP7.1。众所周知,ZendVM是用C语言编写的,各种PHP函数调用的信息在C语言中会用struct/union来表示,所以获取堆栈信息只需要两步:读取PHP进程的内存在内存中找到函数调用栈信息的第一步可以通过ptrace或者process_vm_readv来实现。ptrace是调试器使用的方法,它可以暂停PHP进程,然后读取内存。process_vm_readv可以不挂起进程,性能可能更好,但不靠谱,因为PHP还在执行,栈信息不断变化,很容易读错内存。第二步需要DWARF调试信息。结构大小和字段偏移信息记录在调试信息中。通过这些信息,我们可以准确的读取内存,然后进行分析。原理还是很简单的。下一步是复制vm_stack,并尝试在一个process_vm_readv中获取主要的堆栈信息以增加作用域信息。现在只使用函数名来改进错误处理。当前代码一团糟。了解有关Rust的更多信息