當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; /* 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程式。感興趣的話,可以開啟下面的連線看看。
https://wiki.php.net/rfc/phpdbg
http://phpdbg.com/docs
原文連結:當cpu飆升時,找出php中可能有問題的程式碼行,轉載請註明來源!
相關文章
- 一次線上 CPU 飆升問題的分析解決2017-09-14
- JVM調優jstack找出最耗cpu的執行緒&定位問題程式碼2020-11-19JVMJS執行緒
- cpu飆升排查命令2024-05-30
- CPU 飆升怎麼辦?2024-05-22
- 壞程式碼導致的效能問題大賞:CPU佔用飆到了900%!2021-11-01
- 解決MacBook Pro升級風扇狂轉和CPU飆高問題2021-12-27Mac
- 如何在 Linux 中找出 CPU 佔用高的程式2019-12-15Linux
- CPU飆升?教你1分鐘抓取佔用系統資源的程式2020-03-05
- 微軟將在9月中旬修復CPU利用率飆高的問題2019-09-11微軟
- JVM找出佔用CPU最高的執行緒2020-11-22JVM執行緒
- php程式碼審計之命令執行中windows/linux的差異化問題2021-06-02PHPWindowsLinux
- html檔案中的php程式碼被註釋掉的問題2018-08-31HTMLPHP
- PHP獲取當天凌晨時間戳常用程式碼2016-01-05PHP時間戳
- 程式執行一段時間當機問題 hibernate3.12007-02-25
- 在eclipse中進行php開發中文亂碼問題2017-11-27EclipsePHP
- 使用kibana視覺化報表實時監控你的應用程式,從日誌中找出問題,解決問題2018-06-13視覺化
- 找出消耗CPU最高的程式對應的SQL語句2009-12-13SQL
- 【PHP程式碼審計】Null字元問題2017-09-29PHPNull字元
- php max_execution_time執行時間問題2015-06-16PHP
- [MySQL CPU]線上飆升800%,load達到12的解決過程2014-05-01MySql
- oracle_CPU佔用率高時的問題定位2012-10-10Oracle
- Vue使用中遇到的程式碼問題2018-07-28Vue
- 請教Jive程式碼中的問題2003-10-25
- php編碼問題2012-10-19PHP
- 運維告訴我CPU飆升300%,為什麼我的程式上線就奔潰了2021-05-13運維
- 求教執行EJB程式時出現的問題2006-08-01
- js中找出最大值程式碼例項2017-04-15JS
- Flask 框架中 SQLAlchemy 使用時的亂碼問題2015-11-13Flask框架SQL
- 當單擊DBGrid中的標題欄時,進行排序 (轉)2007-12-13排序
- 你要偷偷學會排查線上CPU飆高的問題,然後驚豔所有人!2021-03-31
- php部署到nginx時遇到的問題2022-06-14PHPNginx
- php5.1x的時區問題!2008-01-03PHP
- Nuxt升級2.0.0時出現的問題2018-10-07UX
- 解決伺服器滿CPU被當礦機問題2018-04-14伺服器
- 在html檔案中執行php程式碼2016-01-21HTMLPHP
- PHP中“==”運算子的安全問題2016-08-10PHP
- PHP中include()的使用問題 (轉)2007-11-12PHP
- PHP 與 JS 的編碼問題2019-04-15PHPJS