快速找出php中可能导致cpu飙升问题的代码行

  用cpu接近100%时,你如何找到导致cpu飙升的原因?我的思路是,首先找到进程正在执行的代码行,从而确定可能有问题的代码段。然后,再仔细分析有问题的代码段,从而找出原因。

  如果你的程序使用的是c、c++编写,那么你可以很容易的找到正在执行的代码行。但是,程序是php编写的,如何找到可能有问题的代码行呢?这个问题就是本文要解决的问题。

  背景知识:

  大家都知道php是一个解释性语言。用户编写的php代码会生成opcode,由解释器引擎去解释执行。在解释执行过程中,有一个全局变量包含了执行过 程中用到的各种数据。它就是executor_globals。在源码的Zend/zend_globals.h 文件中可以找到他的类型定义。

代码如下  

struct _zend_executor_globals {
zval **return_value_ptr_ptr;

zval uninitialized_zval;
zval *uninitialized_zval_ptr;

zval error_zval;
zval *error_zval_ptr;

zend_ptr_stack arg_types_stack;

/* symbol table cache */
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable **symtable_cache_limit;
HashTable **symtable_cache_ptr;

zend_op **opline_ptr;

HashTable *active_symbol_table;
HashTable symbol_table; /* main symbol table */

HashTable included_files; /* files already included */

JMP_BUF *bailout;

int error_reporting;
int orig_error_reporting;
int exit_status;

zend_op_array *active_op_array;

HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
HashTable *zend_constants; /* constants table */

zend_class_entry *scope;
zend_class_entry *called_scope; /* Scope of the calling class */

zval *This;

long precision;

int ticks_count;

zend_bool in_execution;
HashTable *in_autoload;
zend_function *autoload_func;
zend_bool full_tables_cleanup;

/* for extended information support */
zend_bool no_extensions;

#ifdef ZEND_WIN32
zend_bool timed_out;
OSVERSIONINFOEX windows_version_info;
#endif

HashTable regular_list;
HashTable persistent_list;

zend_vm_stack argument_stack;

int user_error_handler_error_reporting;
zval *user_error_handler;
zval *user_exception_handler;
zend_stack user_error_handlers_error_reporting;
zend_ptr_stack user_error_handlers;
zend_ptr_stack user_exception_handlers;

zend_error_handling_t error_handling;
zend_class_entry *exception_class;

/* timeout support */
int timeout_seconds;

int lambda_count;

HashTable *ini_directives;
HashTable *modified_ini_directives;

zend_objects_store objects_store;
zval *exception, *prev_exception;
zend_op *opline_before_exception;
zend_op exception_op[3];

struct _zend_execute_data *current_execute_data;

struct _zend_module_entry *current_module;

zend_property_info std_property_info;

zend_bool active;

void *saved_fpu_cw;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

  这里我们只说两个对我们比较重要的变量,active_op_array 和 current_execute_data。

  active_op_array变量中保存了引擎正在执行的op_array(想了解什么是op_array请点击查看)。在Zend/zend_compile.h中有关于op_array的数据类型的定义。

代码如下  

struct _zend_op_array {
/* Common elements */
zend_uchar type;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
/* END of common elements */

zend_bool done_pass_two;

zend_uint *refcount;

zend_op *opcodes;
zend_uint last, size;

zend_compiled_variable *vars;
int last_var, size_var;

zend_uint T;

zend_brk_cont_element *brk_cont_array;
int last_brk_cont;
int current_brk_cont;

zend_try_catch_element *try_catch_array;
int last_try_catch;

/* static variables support */
HashTable *static_variables;

zend_op *start_op;
int backpatch_count;

zend_uint this_var;

char *filename;
zend_uint line_start;
zend_uint line_end;
char *doc_comment;
zend_uint doc_comment_len;
zend_uint early_binding; /* the linked list of delayed declarations */

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

  看完定义,就不用我多说了把。定义中,filename和 function_name分别保存了正在执行的文件名和方法名。

  current_execute_data保存了正在执行的op_array的execute_data。execute_data保存了每个op_array执行过程中的一些数据。其定义在,Zend/zend_compile.h:

代码如下  
struct _zend_execute_data {
struct _zend_op *opline;
zend_function_state function_state;
zend_function *fbc; /* Function Being Called */
zend_class_entry *called_scope;
zend_op_array *op_array;
zval *object;
union _temp_variable *Ts;
zval ***CVs;
HashTable *symbol_table;
struct _zend_execute_data *prev_execute_data;
zval *old_error_reporting;
zend_bool nested;
zval **original_return_value;
zend_class_entry *current_scope;
zend_class_entry *current_called_scope;
zval *current_this;
zval *current_object;
struct _zend_op *call_opline;
};

  定义中的opline就是正在执行的opcode。opcode的结构定义如下:

代码如下  
struct _zend_op {
opcode_handler_t handler;
znode result;
znode op1;
znode op2;
ulong extended_value;
uint lineno;
zend_uchar opcode;
};

  其中lineno就是opcode所对应的行号。

  示例说明:

  看完上面的数据结构定义,你是否已经知道如何找php正在执行的文件名,方法名和行号呢?如果还有疑问的话,那就接着看下面的例子。创建一个文件test.php,代码如下:

代码如下  
<?php
function test1(){
while(true){
sleep(1);
}
}
test1();
?>

  cli方式执行php脚本,加入执行的进程号为14973。我们使用gdb命令来调试进程。

代码如下  
$sudo gdb -p 14973
(gdb) print (char *)executor_globals.active_op_array->filename
$1 = 0x9853a34 "/home/xinhailong/test/php/test.php"
(gdb) print (char *)executor_globals.active_op_array->function_name
$2 = 0x9854db8 "test1"
(gdb) print executor_globals->current_execute_data->opline->lineno
$3 = 4

  很显然,他正在执行第四行的sleep方法。

  如果上面的方法你感觉麻烦,那你可以使用.gdbinit文件。这个文件在php源码的根目录下。使用方法如下:

代码如下  
$sudo gdb -p 14973
(gdb) source /home/xinhailong/.gdbinit
(gdb) zbacktrace
[0xa453f34] sleep(1) /home/xinhailong/test/php/test.php:4
[0xa453ed0] test1() /home/xinhailong/test/php/test.php:7
(gdb)

  题外话:

  从php5.6开始,php中集成了一个phpdbg的工具。可以像gdb调试c语言程序一样,调试php程序。感兴趣的话,可以打开下面的连接看看

时间: 2024-08-31 08:17:13

快速找出php中可能导致cpu飙升问题的代码行的相关文章

如何快速找出Windows7中的共享文件

  如今,支持Wifi无线上网的电子设备越来越多,除了台式电脑和笔记本外,还有上网本.平板电脑.手机.电子书.电子相册等.在不同设备之间共享视频.音乐或文件可以不受位置的约束.不过,我们开启共享很简单,但是共享多了后,你还知道你电脑里有哪些文件是已经共享,在其他设备上可以看到,又有哪些文件别人有写入权限?如果我们的无线网络被人入侵或者外出连接到了别人的网络,自己的隐私和数据安全就会受到很大的威胁. 下面就让小编来给您介绍一下Win7系统里快速找出共享文件的几种方法吧. 方法一.资源管理器文件夹

快速找出Excel中错误的身份证信息

作为办公人员,经常要编写关于职工信息档案的表格,其中最常输入的数据就是身份证号码,由于人员众多,输入确实麻烦,一不小心就可能把员工的出生日期弄错了,这可是关系到每个员工的切身利益,如工龄.社会保险金等.要是逐一验证那可是一件让人头疼的事情.下面笔者就教大家一招,通过此方法就能够很快查找出Excel表中错误的身份证号码.下面以"XXX公司员工信息统计表"为例. 首先从B列的身份证号码(注:输入前必须将该列单元格格式统一为"文本")中提取出生日期到C列,以C3为例,选中

快速找出Windows7中的共享文件

方法一.资源管理器文件夹 我们只需要如下设置就可以查看文件是否共享. 将文件夹以"详细信息"视图显示,然后在文件夹的标题行中点击右键,选择"其他"; 在"选择详细信息"列表中找到并选择"共享状态"和"已共享"两项,并确认-- 这时,我们就可以在详细信息视图中看到当前文件夹中,有哪些文件夹已经共享,哪些文件夹没有共享; "已共享":表示该文件夹已经通过Windows 的文件共享功能共享到网

快速找出局域网的中毒电脑

在局域网环境中上网的朋友会经常碰到无故断线的情况,并且检查电脑也检查不出什么原因.其实出现这种情况,大部分情况下都是局域网中的某一台电脑感染了ARP类型的病毒所至.感染病毒,电脑一一杀毒,电脑过多的情况下显然很费时费力.现在就告诉你这三招两式,快速找出局域网中的"毒瘤". 小提示: ARP:Address Resolution Protocol的缩写,即地址解析协议.ARP负责将电脑的IP地址转换为对应的物理地址,即网卡的MAC地址.当发生ARP欺骗时,相关主机会收到错误的数据,从而造

如何快速找出存在问题的交互设计

当我们在没有数据,没有时间去了解具体情况,没有多余的精力和资金做各种测试,在构思阶段想要验证自己想法的时候,如何用最快速的方法发现有问题的设计并把他扼杀在摇篮中?接下来的内容应该对你有所帮助. 我写正文前,我希望大家能够明白不好的设计是有多种原因造成的,我写这篇文章的目的是想探讨下如何快速的鉴别出不好的设计,并避免这样的设计发生在自己身上.但有时候明知道是不好的设计却还是发生在自己身上了--原因你懂的.下面说正题: 我拿来举例子的这一家网站算是比较著名的威客网站,就是发布任务接任务的网站.我是第

JavaScript通过this变量快速找出用户选中radio按钮的方法

 这篇文章主要介绍了JavaScript通过this变量快速找出用户选中radio按钮的方法,涉及javascript中this变量的使用技巧,非常具有实用价值,需要的朋友可以参考下     本文实例讲述了JavaScript通过this变量快速找出用户选中radio按钮的方法.分享给大家供大家参考.具体分析如下: 下面的JS代码通过this变量结合radio按钮的onchange事件快速找出用户选择的哪一个radio按钮 ? 1 2 3 4 5 6 7 8 9 10 11 <script>

Powershell小技巧之找出脚本中的错误_PowerShell

找出脚本之中的语法错误从来就不是轻松的事情,但是可以这样去筛选: filter Test-SyntaxError { $text = Get-Content -Path $_.FullName if ($text.Length -gt 0) { $err = $null $null = [System.Management.Automation.PSParser]::Tokenize($text, [ref] $err) if ($err) { $_ } } } 这个脚本中,你可以快速扫描一个目

[华为机试练习题]61.找出字符串中第一个出现次数最多的字符

题目 描述: 找出字符串中第一个出现次数最多的字符 详细描述: 接口说明 原型: bool FindChar(char* pInputString, char* pChar); 输入参数: char* pInputString:字符串 输出参数(指针指向的内存区域保证有效): char* pChar:出现次数最多的字符 返回值: false 异常失败 true 输出成功 练习阶段: 初级 代码 /*--------------------------------------- * 日期:2015

编程c语言-新手OJ, 找出字符串中出现最多的字母,本机运行正确, 但是wrong answer, 求大神指点

问题描述 新手OJ, 找出字符串中出现最多的字母,本机运行正确, 但是wrong answer, 求大神指点 Description 钟Sir是一个迷信的(superstitious)家伙.他相信每一个字符串(string)里都有一个幸运字符.我们可以通过以下方法找到这个字符.例如,在字符串abbccc中,c 出现的次数最多,所以这个幸运字符就是 c 啦!(>_<) ?(钟Sir的想法好简单啊-) Input 第一行是测试数据的组数n,接下来的每组测试数据占一行,每行数据不超过1000个字符且