ホームページ >バックエンド開発 >PHPチュートリアル >GDB を使用して PHP コードをデバッグし、PHP コードの無限ループの問題を解決する_PHP チュートリアル

GDB を使用して PHP コードをデバッグし、PHP コードの無限ループの問題を解決する_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 10:05:501301ブラウズ

GDB を使用して PHP コードをデバッグし、PHP コードの無限ループ問題を解決します

最近、同僚が Swoole Server の問題を解決するのを手伝っていたとき、1 つのワーカー プロセスが常に R 状態にあり、CPU 消費量がとても高かったです。暫定的な結論は、PHP コードで無限ループが発生するということです。

次のコードは、PHP の無限ループ問題を解決する方法を示しています。

コードは次のとおりです:


#デッドループ.php
$array = array();
for($i = 0; $i {
$array[] = $i;
}
include __DIR__."/include.php";
#include.php
その間(1)
{
usleep(10);
$keys = array_flip($array);
$index = array_search(rand(1500, 9999), $array);
$str = str_repeat('A', $index);
$strb = テスト($index, $str);
}
関数テスト($index, $str)
{
return str_replace('A', 'B', $str);
}

次のように ps aux を通じてプロセス ID とステータスを取得し、gdb -p process ptrace tracking を使用して、bt コマンドを通じてコールスタックを取得します

コードは次のとおりです:


htf 3834 2.6 0.2 166676 22060 ポイント/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)
/home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:1485
で #1 0x00000000008cd643 _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) /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) /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2436
#3 _zval_ptr_dtor の 0x00000000008eda0a (zval_ptr=0x25849a0, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182)
/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c:437
で /home/htf/workspace/php-5.4.27/Zend/zend_variables.c:182 の _zval_ptr_dtor_wrapper (zval_ptr=0x25849a0) の #4 0x00000000008fe687
#5 0x000000000091259f zend_hash_destroy (ht=0x7f7263f6e380) (/home/htf/workspace/php-5.4.27/Zend/zend_hash.c:560)
#6 _zval_dtor_func の 0x00000000008fe2c5 (zvalue=0x7f726426fe50, __zend_filename=0xeea290 "/home/htf/workspace/php-5.4.27/Zend/zend_execute.c", __zend_lineno=901)
/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)
/home/htf/workspace/php-5.4.27/Zend/zend_variables.h:35
にあります #8 0x0000000000939747 zend_assign_to_variable (variable_ptr_ptr=0x7f7263f8e738, value=0x7f726426f6a8) at /home/htf/workspace/php-5.4.27/Zend/zend_execute.c:901
/home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:33168 の ZEND_ASSIGN_SPEC_CV_VAR_HANDLER (execute_data=0x7f726d04b2a8) の #9 0x0000000000997ee5
#10 0x000000000093b5fd の実行 (op_array=0x21d58b0) (/home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410)
#11 0x0000000000901692 zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/htf/workspace/php-5.4.27/Zend/zend.c:1315
#12 0x000000000087926a php_execute_script (primary_file=0x7ffffe0038d0) (/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 メイン (argc=2, argv=0x7ffffe004d18) の 0x00000000009a4491 /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) /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) /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2425
#2 0x0000000000911d85 _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) /home/htf/workspace/php-5.4.27/Zend/zend_hash.c: 412
#3 zif_array_flip の 0x00000000007767e1 (ht=1、return_value=0x7f726424ea68、return_value_ptr=0x0、this_ptr=0x0、return_value_used=1)
/home/htf/workspace/php-5.4.27/ext/standard/array.c:2719
にあります #4 zend_do_fcall_common_helper_SPEC (execute_data=0x7f726d04b2a8) の 0x000000000093c03e (/home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:643)
/home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:2233 の ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x7f726d04b2a8) の #5 0x00000000009400e6
#6 0x000000000093b5fd の実行 (op_array=0x21d58b0) (/home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410)

2 回の BT 情報とは異なり、これはプログラムが別の場所で中断されたためです。この行を実行 (oparray=0x21d58b0) します。これは、PHP が oparray を実行するためのエントリです。gdb の下に 6 を入力します。入手可能です)。

代码如下:

(gdb) f 6
#6 0x000000000093b5fd の実行 (op_array=0x21d58b0) (/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 ' 02'、function_name = 0x7f726d086540 "テスト"、スコープ = 0x0、fn_flags = 134217728、プロトタイプ = 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、リテラル = 0x7f726424eae0、last_literal = 4、run_time_cache = 0x7f726450bfb0、last_cache_slot = 1、予約済み = {0x0, 0x0, 0x0, 0x0}}

ここのファイル名から、op_array が 1 つの PHP ファイルであることがわかります。その後、f 0 を現在の位置に入力します。

代码如下:

(gdb) p **executor_globals.opline_ptr
$4 = {ハンドラー = 0x93ff9c 、op1 = {定数 = 1680133296、変数 = 1680133296、数値 = 1680133296、ハッシュ = 140129283132592、opline_num = 1680133296、
jmp_addr = 0x7f726424ccb0、zv = 0x7f726424ccb0、リテラル = 0x7f726424ccb0、ptr = 0x7f726424ccb0}、op2 = {定数 = 0、var = 0、num = 0、ハッシュ = 0、opline_num = 0、jmp_addr = 0 ×0、
zv = 0x0、リテラル = 0x0、ptr = 0x0}、結果 = {constant = 32、var = 32、num = 32、hash = 32、opline_num = 32、jmp_addr = 0x20、zv = 0x20、リテラル = 0x20、ptr = 0x20}、
拡張値 = 1、行番号 = 5、オペコード = 60 '

ここの lineno は、OPCODE にあるコード行数を示します。GDB を使用すると、ここでさらに多くの情報を参照できます。 。

zbacktraceの使用

zend 官は、命令がカプセル化され、php 関数の調整関係を直接参照できる gdb のスクリプトを提供しています。php ソース コードのルート ディレクトリに 1 つの .gdbinit があります。

代码如下:

ソース your_php_src_path/.gdbinit

zバックトレース



PHP 関数の調整用スタックを直接参照できます。 以上が本書のすべての内容です、皆様のご理解とご協力をお願いいたします。

www.bkjia.com本当http://www.bkjia.com/PHPjc/962927.html技術記事 GDB を使用して PHP コードをデバッグし、PHP コードの無限ループ問題を解決する 最近、同僚が Swoole Server の問題を解決するのを手伝っていたとき、1 つのワーカー プロセスが常に R 状態になっていて、CPU の消費量が非常に高いことがわかりました。 ...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。