首页 存档 技术 查看内容

当cpu飙升时,找出php中可能有问题的代码行

2018-3-30 13:00 |来自: 互联网 253 0

摘要: (点击上方公众号,可快速关注) 来自:淘宝搜索技术博客 链接:http://www.searchtb.com/2014/04/褰揷pu椋欏崌鏃讹紝鎵惧嚭php涓?彲鑳芥湁闂??鐨勪唬鐮佽?.html 当你发现一个平时占用cpu比较少的进程突然间 ...

(点击上方公众号,可快速关注)

来自:淘宝搜索技术博客

链接:http://www.searchtb.com/2014/04/褰揷pu椋欏崌鏃讹紝鎵惧嚭php涓?彲鑳芥湁闂??鐨勪唬鐮佽?.html


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

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

背景知识:

如果你对c语言不熟悉的话,可以略过,直接看 示例演示。

大家都知道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,代码如下:

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部