当你发现一个平时占用cpu比较少的进程突然间占用cpu接近100%时,你如何找到导致cpu飙升的原因?我的思路是,首先找到进程正在执行的代码行,从而确定可能有问题的代码段。然后,再仔细分析有问题的代码段,从而找出原因。 如果你的程序使用的是c、c++编写,那么你可以很容易的找到正在执行的代码行。但是,程序是php编写的,如何找到可能有问题的代码行呢?这个问题就是本文要解决的问题。 背景知识:
大 家都知道php是一个解释性语言。用户编写的php代码会生成opcode,由解释器引擎去解释执行。在解释执行过程中,有一个全局变量包含了执行过程中 用到的各种数据。它就是executor_globals。在源码的Zend/zend_globals.h 文件中可以找到他的类型定义。
这里我们只说两个对我们比较重要的变量,active_op_array 和 current_execute_data。
看完定义,就不用我多说了把。定义中,filename和 function_name分别保存了正在执行的文件名和方法名。 current_execute_data保存了正在执行的op_array的execute_data。execute_data保存了每个op_array执行过程中的一些数据。其定义在,Zend/zend_compile.h:
定义中的opline就是正在执行的opcode。opcode的结构定义如下:
其中lineno就是opcode所对应的行号。 示例说明: 看完上面的数据结构定义,你是否已经知道如何找php正在执行的文件名,方法名和行号呢?如果还有疑问的话,那就接着看下面的例子。创建一个文件test.php,代码如下:
cli方式执行php脚本,加入执行的进程号为14973。我们使用gdb命令来调试进程。
很显然,他正在执行第四行的sleep方法。 如果上面的方法你感觉麻烦,那你可以使用.gdbinit文件。这个文件在php源码的根目录下。使用方法如下:
题外话: 从php5.6开始,php中集成了一个phpdbg的工具。可以像gdb调试c语言程序一样,调试php程序。感兴趣的话,可以打开下面的连接看看。 |