快速找出php中可能导致cpu飙升问题的代码行
来源: 阅读:716 次 日期:2014-12-09 10:58:55
温馨提示: 小编为您整理了“快速找出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程序。感兴趣的话,可以打开下面的连接看看

更多信息请查看IT技术专栏

更多信息请查看网络编程
由于各方面情况的不断调整与变化, 提供的所有考试信息和咨询回复仅供参考,敬请考生以权威部门公布的正式信息和咨询为准!

2025国考·省考课程试听报名

  • 报班类型
  • 姓名
  • 手机号
  • 验证码
关于我们 | 联系我们 | 人才招聘 | 网站声明 | 网站帮助 | 非正式的简要咨询 | 简要咨询须知 | 加入群交流 | 手机站点 | 投诉建议
工业和信息化部备案号:滇ICP备2023014141号-1 云南省教育厅备案号:云教ICP备0901021 滇公网安备53010202001879号 人力资源服务许可证:(云)人服证字(2023)第0102001523号
云南网警备案专用图标
联系电话:0871-65317125(9:00—18:00) 获取招聘考试信息及咨询关注公众号:
咨询QQ:526150442(9:00—18:00)版权所有:
云南网警报警专用图标
Baidu
map