目录
使用GDB调试PHP代码,解决PHP代码死循环问题,gdbphp
首页 后端开发 php教程 使用GDB调试PHP代码,解决PHP代码死循环问题,gdbphp_PHP教程

使用GDB调试PHP代码,解决PHP代码死循环问题,gdbphp_PHP教程

Jul 13, 2016 am 10:05 AM
gdb 死循环 调试php代码

使用GDB调试PHP代码,解决PHP代码死循环问题,gdbphp

最近在帮同事解决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函数的调用堆栈。

以上就是本文的全部内容了,希望大家能够喜欢。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/963122.htmlTechArticle使用GDB调试PHP代码,解决PHP代码死循环问题,gdbphp 最近在帮同事解决Swoole Server问题时,发现有1个worker进程一直处于R的状态,而且CPU耗时非...
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

使用GDB调试Linux内核的常用配置技巧 使用GDB调试Linux内核的常用配置技巧 Jul 05, 2023 pm 01:54 PM

使用GDB调试Linux内核的常用配置技巧引言:在Linux开发中,使用GDB调试内核是一项非常重要的技能。GDB是一款功能强大的调试工具,可以帮助开发者快速定位和解决内核中的bug。本文将介绍一些常用的GDB配置技巧,以及如何使用GDB调试Linux内核。一、配置GDB环境首先,我们需要在Linux系统上配置GDB的环境。请确保你的系统已经安装了GDB工具

Linux下使用GDB调试嵌入式ARM程序的常见配置方法 Linux下使用GDB调试嵌入式ARM程序的常见配置方法 Jul 05, 2023 am 08:10 AM

Linux下使用GDB调试嵌入式ARM程序的常见配置方法嵌入式系统作为一种特殊的计算机系统,通常集成在电子设备中,用于控制和管理硬件资源。为了调试和分析嵌入式系统的运行状况,我们需要使用专门的工具。其中,GDB是一种常用的开源调试器,它能够在嵌入式系统上运行并与程序进行通信。本文将介绍在Linux下使用GDB调试嵌入式ARM程序的常见配置方法,并给出代码示例

如何使用 GDB 调试 Golang 函数? 如何使用 GDB 调试 Golang 函数? Apr 18, 2024 am 08:00 AM

使用GDB调试Go函数步骤如下:安装GDB和Go调试包。启用调试信息编译程序。使用GDB启动程序。设置断点。使用run命令启动程序。使用调试命令进行调试。

如何解决C++开发中的死循环问题 如何解决C++开发中的死循环问题 Aug 22, 2023 am 08:53 AM

如何解决C++开发中的死循环问题在C++开发中,死循环是一种非常常见却又非常棘手的问题。当程序陷入死循环时,会导致程序无法正常执行,甚至可能导致系统崩溃。因此,解决死循环问题是C++开发中必不可少的技能之一。本文将介绍一些常见的解决死循环问题的方法。检查循环条件死循环的最常见原因之一就是循环条件不正确。当循环条件一直为真时,循环就会一直执行下去,导致陷入死循

Linux下使用GDB调试多线程程序的常见配置方法 Linux下使用GDB调试多线程程序的常见配置方法 Jul 04, 2023 pm 02:49 PM

Linux下使用GDB调试多线程程序的常见配置方法引言:在多线程编程中,调试是一项必不可少的工作。GDB是一个功能强大的调试器,可以帮助我们定位和解决多线程程序中出现的错误。本文将介绍在Linux下使用GDB调试多线程程序的常见配置方法,并配备代码示例,希望能帮助读者更好地理解和运用GDB。一、安装GDB首先,我们需要在Linux系统中安装GDB。在终端中输

Linux系统常用的调试工具和技巧 Linux系统常用的调试工具和技巧 Feb 23, 2024 pm 02:40 PM

在Linux系统中,调试是程序开发和维护过程中至关重要的一环。为了协助开发者更有效地进行调试,Linux提供了多种强大的调试工具和技术。本文将简要介绍一些常用的Linux调试工具和技巧,以助开发者更好地进行调试。一、调试工具1.gdb在Linux系统中,gdb被广泛用作调试工具之一,它有助于开发者追踪程序崩溃的原因,并提供一系列命令来检查程序状态、修改变量和执行代码等操作。要启动调试,可以使用以下命令。$gdb./program其中,`./program`表示要调试的可执行文件。一旦gdb启动,

如何解决:Java算法错误:死循环 如何解决:Java算法错误:死循环 Aug 25, 2023 pm 10:12 PM

如何解决:Java算法错误:死循环引言:在编写Java程序的过程中,我们经常会遇到各种错误和异常。其中,死循环是一种常见的问题,它会使程序陷入无限循环的状态,导致程序无法正常执行。在本文中,我们将讨论如何解决Java算法中的死循环问题,并提供一些示例代码。一、死循环的定义和原因:死循环指的是程序中的循环结构没有正常终止的条件,导致程序在此循环内无限循环执行。

win10如何自动修复死循环的解决方法 win10如何自动修复死循环的解决方法 Dec 27, 2023 pm 04:04 PM

win10自动修复死循环是很多用户的常见问题,给大部分用户都添了不少的麻烦,那么有没有按键可以直接让他退出呢?下面就一起来看看详细的教程吧。win10自动修复死循环按f几跳出:主要看电脑的品牌,不同品牌不同的按键,常用的就是F9和F11,联想的一般是F12开机出现联想LOGO画面的时候,按下F2,就进入联想电脑拯救系统,这时候选择联想一键恢复,或直接按键盘上的“R”键,这时又会出现一个画面,按左右键选择“继续”,这时候你就进入“联想一键恢复”。进去有三个选项,即系统恢复、系统备份和备份卸载,根据

See all articles