加入收藏 | 设为首页 | 会员中心 | 我要投稿 汽车网 (https://www.0577qiche.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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

发布时间:2023-09-13 13:58:45 所属栏目:PHP教程 来源:
导读:cpu飙升占100%不但是与数据库或硬盘的io输入有关,但程序也是一个非常重要的地方了,今天小编找到一个代码可以测试你的php引起cpu占100%问题的解决办法,有兴趣的朋友可进入参考.

用cpu接近100%时,你如何找到导致cpu
cpu飙升占100%不但是与数据库或硬盘的io输入有关,但程序也是一个非常重要的地方了,今天小编找到一个代码可以测试你的php引起cpu占100%问题的解决办法,有兴趣的朋友可进入参考.

用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;  //开源软件:Cuoxin.com 
    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语言程序一样.

(编辑:汽车网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章