最近在帮同事解决Swoole Server问题时,发现有1个worker进程一直处于R的状态,而且CPU耗时非常高。初步断定是PHP代码中发生死循环。
下面通过一段代码展示如何解决PHP死循环问题。
代码如下:
#dead_loop.php
$array = array();
for($i = 0; $i
{
$array[] = $i;
}
include __DIR__."/include.php";
#include.php
while(1)
{
usleep(10);
$keys = array_flip($array);
$index = array_search(rand(1500, 9999), $array);
$str = str_repeat('A', $index);
$strb = test($index, $str);
}
function test($index, $str)
{
return str_replace('A', 'B', $str);
}
通过ps aux得到进程ID和状态如下,使用gdb -p 进程ptrace跟踪,通过bt命令得到调用栈
代码如下:
htf 3834 2.6 0.2 166676 22060 pts/12 R+ 10:50 0:12 php dead_loop.php
gdb -p 3834
(gdb) bt
#0 0x00000000008cc03f in zend_mm_check_ptr (heap=0x1eaa2c0, ptr=0x2584910, silent=1, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c",
__zend_lineno=182, __zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437)
at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:1485
#1 0x00000000008cd643 in _zend_mm_free_int (heap=0x1eaa2c0, p=0x2584910, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182,
__zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2064
#2 0x00000000008cebf7 in _efree (ptr=0x2584910, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182,
__zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2436
#3 0x00000000008eda0a in _zval_ptr_dtor (zval_ptr=0x25849a0, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182)
at /home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c:437
#4 0x00000000008fe687 in _zval_ptr_dtor_wrapper (zval_ptr=0x25849a0) at /home/htf/workspace/php-5.4.27/Zend/zend_variables.c:182
#5 0x000000000091259f in zend_hash_destroy (ht=0x7f7263f6e380) at /home/htf/workspace/php-5.4.27/Zend/zend_hash.c:560
#6 0x00000000008fe2c5 in _zval_dtor_func (zvalue=0x7f726426fe50, __zend_filename=0xeea290 "/home/htf/workspace/php-5.4.27/Zend/zend_execute.c", __zend_lineno=901)
at /home/htf/workspace/php-5.4.27/Zend/zend_variables.c:45
#7 0x0000000000936656 in _zval_dtor (zvalue=0x7f726426fe50, __zend_filename=0xeea290 "/home/htf/workspace/php-5.4.27/Zend/zend_execute.c", __zend_lineno=901)
at /home/htf/workspace/php-5.4.27/Zend/zend_variables.h:35
#8 0x0000000000939747 in zend_assign_to_variable (variable_ptr_ptr=0x7f7263f8e738, value=0x7f726426f6a8) at /home/htf/workspace/php-5.4.27/Zend/zend_execute.c:901
#9 0x0000000000997ee5 in ZEND_ASSIGN_SPEC_CV_VAR_HANDLER (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:33168
#10 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410
#11 0x0000000000901692 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/htf/workspace/php-5.4.27/Zend/zend.c:1315
#12 0x000000000087926a in php_execute_script (primary_file=0x7ffffe0038d0) at /home/htf/workspace/php-5.4.27/main/main.c:2502
#13 0x00000000009a32e3 in do_cli (argc=2, argv=0x7ffffe004d18) at /home/htf/workspace/php-5.4.27/sapi/cli/php_cli.c:989
#14 0x00000000009a4491 in main (argc=2, argv=0x7ffffe004d18) at /home/htf/workspace/php-5.4.27/sapi/cli/php_cli.c:1365
执行gdb后,死循环的进程会变成T的状态,表示正在Trace。这个是独占的,所以不能再使用strace/gdb或者其他ptrace工具对此进程进行调试。另外此进程会中断执行。gdb输入c后,程序继续向下运行。然后再次按下ctrl + c中断程序。 通过bt命令查看进程的调用栈。
代码如下:
(gdb) bt
#0 _zend_mm_alloc_int (heap=0x1eaa2c0, size=72, __zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719,
__zend_orig_filename=0xee5a38 "/home/htf/workspace/php-5.4.27/Zend/zend_hash.c", __zend_orig_lineno=412) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:1895
#1 0x00000000008ceb86 in _emalloc (size=72, __zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719,
__zend_orig_filename=0xee5a38 "/home/htf/workspace/php-5.4.27/Zend/zend_hash.c", __zend_orig_lineno=412) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2425
#2 0x0000000000911d85 in _zend_hash_index_update_or_next_insert (ht=0x2257a10, h=3972, pData=0x7ffffe0012b0, nDataSize=8, pDest=0x0, flag=1,
__zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719) at /home/htf/workspace/php-5.4.27/Zend/zend_hash.c:412
#3 0x00000000007767e1 in zif_array_flip (ht=1, return_value=0x7f726424ea68, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
at /home/htf/workspace/php-5.4.27/ext/standard/array.c:2719
#4 0x000000000093c03e in zend_do_fcall_common_helper_SPEC (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:643
#5 0x00000000009400e6 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:2233
#6 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410
两次的BT信息不一样,这是因为程序在不同的位置中断。看到execute (oparray=0x21d58b0) 这一行,这里就是PHP执行oparray的入口了。gdb下输入f 6,(通过调用栈编号可得)。
代码如下:
(gdb) f 6
#6 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410
410 if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0) {
(gdb) p *op_array
$2 = {type = 2 '\002', function_name = 0x7f726d086540 "test", scope = 0x0, fn_flags = 134217728, prototype = 0x0, num_args = 2, required_num_args = 2, arg_info = 0x7f726d086bd8,
refcount = 0x7f726d0870f0, opcodes = 0x7f726424d600, last = 8, vars = 0x7f726424e890, last_var = 2, T = 1, brk_cont_array = 0x0, last_brk_cont = 0, try_catch_array = 0x0,
last_try_catch = 0, static_variables = 0x0, this_var = 4294967295, filename = 0x7f726424ba38 "/home/htf/wwwroot/include.php", line_start = 12, line_end = 15, doc_comment = 0x0,
doc_comment_len = 0, early_binding = 4294967295, literals = 0x7f726424eae0, last_literal = 4, run_time_cache = 0x7f726450bfb0, last_cache_slot = 1, reserved = {0x0, 0x0, 0x0, 0x0}}
这里的filename就能看到op_array是哪个PHP文件的。然后输入f 0进入当前位置。
代码如下:
(gdb) p **executor_globals.opline_ptr
$4 = {handler = 0x93ff9c , op1 = {constant = 1680133296, var = 1680133296, num = 1680133296, hash = 140129283132592, opline_num = 1680133296,
jmp_addr = 0x7f726424ccb0, zv = 0x7f726424ccb0, literal = 0x7f726424ccb0, ptr = 0x7f726424ccb0}, op2 = {constant = 0, var = 0, num = 0, hash = 0, opline_num = 0, jmp_addr = 0x0,
zv = 0x0, literal = 0x0, ptr = 0x0}, result = {constant = 32, var = 32, num = 32, hash = 32, opline_num = 32, jmp_addr = 0x20, zv = 0x20, literal = 0x20, ptr = 0x20},
extended_value = 1, lineno = 5, opcode = 60 '
这里的lineno表示OPCODE所在的代码行数,可以到对应文件里去看下是哪行代码。使用GDB可以查看到更多的信息,这里就不再一一介绍了,有兴趣各位可以自行尝试。
zbacktrace的使用
zend官方提供了一个gdb的脚本,对指令进行了封装,可以直接看到php函数的调用关系。在php源代码包的根目录中有一个.gdbinit。使用
代码如下:
source your_php_src_path/.gdbinit
zbacktrace
可以直接看到PHP函数的调用堆栈。
以上就是本文的全部内容了,希望大家能够喜欢。

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP不是在消亡,而是在不斷適應和進化。 1)PHP從1994年起經歷多次版本迭代,適應新技術趨勢。 2)目前廣泛應用於電子商務、內容管理系統等領域。 3)PHP8引入JIT編譯器等功能,提升性能和現代化。 4)使用OPcache和遵循PSR-12標準可優化性能和代碼質量。

PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。

在PHP中,trait適用於需要方法復用但不適合使用繼承的情況。 1)trait允許在類中復用方法,避免多重繼承複雜性。 2)使用trait時需注意方法衝突,可通過insteadof和as關鍵字解決。 3)應避免過度使用trait,保持其單一職責,以優化性能和提高代碼可維護性。

依賴注入容器(DIC)是一種管理和提供對象依賴關係的工具,用於PHP項目中。 DIC的主要好處包括:1.解耦,使組件獨立,代碼易維護和測試;2.靈活性,易替換或修改依賴關係;3.可測試性,方便注入mock對象進行單元測試。

SplFixedArray在PHP中是一種固定大小的數組,適用於需要高性能和低內存使用量的場景。 1)它在創建時需指定大小,避免動態調整帶來的開銷。 2)基於C語言數組,直接操作內存,訪問速度快。 3)適合大規模數據處理和內存敏感環境,但需謹慎使用,因其大小固定。

PHP通過$\_FILES變量處理文件上傳,確保安全性的方法包括:1.檢查上傳錯誤,2.驗證文件類型和大小,3.防止文件覆蓋,4.移動文件到永久存儲位置。

JavaScript中處理空值可以使用NullCoalescingOperator(??)和NullCoalescingAssignmentOperator(??=)。 1.??返回第一個非null或非undefined的操作數。 2.??=將變量賦值為右操作數的值,但前提是該變量為null或undefined。這些操作符簡化了代碼邏輯,提高了可讀性和性能。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

禪工作室 13.0.1
強大的PHP整合開發環境

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境