当cpu飙升时,找出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;
 
     
      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;       
 
      HashTable included_files;   
 
      JMP_BUF *bailout;
 
      int error_reporting;
      int orig_error_reporting;
      int exit_status;
 
      zend_op_array *active_op_array;
 
      HashTable *function_table; 
      HashTable *class_table;       
      HashTable *zend_constants; 
 
      zend_class_entry *scope;
      zend_class_entry *called_scope;
 
      zval *This;
 
      long precision;
 
      int ticks_count;
 
      zend_bool in_execution;
      HashTable *in_autoload;
      zend_function *autoload_func;
      zend_bool full_tables_cleanup;
 
     
      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;
 
     
      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 {
     
      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;
     
 
      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;
 
     
      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;
 
      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;
      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,代码如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Boss_Commander

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值