加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php怎么进行内存调试

发布时间:2022-07-21 13:46:06 所属栏目:PHP教程 来源:互联网
导读:内存调试 本章是有关PHP源代码的内存调试的简要介绍。 这不是一门完整的课程:内存调试并不难, 但是你需要一些它的使用经验,大量的练习可能是你在设计任何C编写的代码时都必须要做的事情。我们将在这里介绍一个非常著名的内存调试器: valgrind; 以及如何将
  内存调试
  本章是有关PHP源代码的内存调试的简要介绍。 这不是一门完整的课程:内存调试并不难, 但是你需要一些它的使用经验,大量的练习可能是你在设计任何C编写的代码时都必须要做的事情。我们将在这里介绍一个非常著名的内存调试器: valgrind; 以及如何将其与PHP一起使用来调试内存问题。
 
  相关学习推荐:PHP编程从入门到精通
 
  Valgrind简介
  Valgrind是许多Unix环境下使用的知名工具,可以在任何C/C++编写的软件中调试许多常见的内存问题。 Valgrind 是有关内存调试的多功能前端工具。最常用的底层工具称为 “memcheck”。它的工作方式是用自己的堆分配替换每个libc的堆分配,并跟踪你对它们所做的事情。你可能还会对 “massif” 感兴趣: 它是一个内存跟踪器,对于了解程序的常规堆内存使用情况非常有用。
 
 
  Valgrind 不是你可能会使用的唯一工具,但是是最常用的工具。还有其他工具,例如 Dr.Memory、LeakSanitizer、Electric Fence、AddressSanitizer。
 
  在开始之前
  以下是在存储器调试方面具有良好经验并减轻发现缺陷并减少调试时间的机会所需的步骤:
 
  -您应始终使用PHP的调试版本。尝试调试生产版本中的内存是无关紧要的。
  -您应该始终在 USE_ZEND_ALLOC = 0 环境下启动调试器。您可能已经在Zend Memory Manager章节中了解到,此环境var会在当前进程启动时禁用ZendMM。强烈建议在启动内存调试器时这样做。完全绕过ZendMM有助于了解valgrind生成的跟踪。
  -强烈建议在环境 ZEND_DONT_UNLOAD_MODULES = 1 下启动内存调试器。这样可以防止PHP在过程结束时卸载扩展程序的.so文件。这是为了获得更好的valgrind报告跟踪;如果在valgrind将要显示其错误时PHP将卸载扩展名,则稍后将不完整,因为从中获取信息的文件不再是进程内存映像的一部分。
  -您可能需要一些抑制措施。当您告诉PHP在过程结束时不要卸载其扩展名时,可能会在valgrind输出中给您误报。将检查PHP扩展是否泄漏,如果您在平台上误报,则可以使用抑制功能将其关闭像这样。可以根据这样的示例随意编写自己的文件。
  -与Zend Memory Manager相比,Valgrind显然是更好的工具,可以查找泄漏和其他与内存相关的问题。您应该始终在代码上运行valgrind,这实际上是每个C程序员都必须执行的步骤。无论是因为崩溃而想要找到并调试它,还是作为看起来好像没有任何坏处的高质量工具来运行它,valgrind都是这种工具,它可以指出隐藏的瑕疵,准备好将其吹拂一次或以后。即使您认为代码似乎一切都很好,也可以使用它:您可能会感到惊讶。
 
  Warning
 
  您**必须在程序上使用valgrind(或任何内存调试器)。对于每个强大的C程序,要不调试内存就不可能100%充满信心。内存错误会导致有害的安全问题,并且程序崩溃通常取决于许多参数,通常是随机的。
 
  内存泄漏检测示例
  入门
  Valgrind是一个完整的堆内存调试器。它还可以调试过程内存映射和功能堆栈。请在其文档中获取更多信息。
 
  让我们去检测动态内存泄漏,并尝试一个简单的,最常见的泄漏:
 
 
 
 
 
  PHP_RINIT_FUNCTION(pib)
 
  {
 
      void *foo = emalloc(128);
 
  }
 
  上面的代码每次请求都会泄漏128字节,因为它没有与此类缓冲区有关的efree()相关调用。由于它是对emalloc()的调用,因此会通过Zend Memory Manager,因此稍后会警告我们就像我们在ZendMM章节中看到的那样。我们还要看看valgrind是否可以注意到泄漏:
 
 
 
  > ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0 valgrind --leak-check=full --suppressions=/path/to/suppression
 
  ==28104==    by 0xA3701E: __zend_malloc (zend_alloc.c:2820)
 
  ==28104==    by 0xA362E7: _emalloc (zend_alloc.c:2413)
 
  ==28104==    by 0xE896F99: zm_activate_pib (pib.c:1880)
 
  ==28104==    by 0xA79F1B: zend_activate_modules (zend_API.c:2537)
 
  ==28104==    by 0x9D31D3: php_request_startup (main.c:1673)
 
  ==28104==    by 0xB5909A: do_cli (php_cli.c:964)
 
  ==28104==    by 0xB5A423: main (php_cli.c:1381)
 
   
 
  ==28104== LEAK SUMMARY:
 
  ==28104==    definitely lost: 128 bytes in 1 blocks
 
  ==28104==    indirectly lost: 0 bytes in 0 blocks
 
  ==28104==    possibly lost: 0 bytes in 0 blocks
 
  ==28104==    still reachable: 0 bytes in 0 blocks
 
  ==28104==    suppressed: 7,883 bytes in 40 blocks
 
  在我们看来,“绝对失落”是我们必须关注的。
 
  Note
 
  有关memcheck输出的不同字段的详细信息,请查看。
 
  Note
 
  我们使用USE_ZEND_ALLOC = 0禁用并完全绕过Zend Memory Manager。对其API的每次调用(例如emalloc())将直接导致libc调用,就像我们在calgrind输出堆栈帧上可以看到的那样。
 
  Valgrind抓住了我们的漏洞。
 
  很容易,现在我们可以使用持久分配(也就是绕过ZendMM并使用传统libc的动态内存分配)来产生泄漏。走:
 
 
  PHP_RINIT_FUNCTION(pib)
 
  {
 
      void *foo = malloc(128);
 
  ==28758==    by 0xE896F82: zm_activate_pib (pib.c:1880)
 
  ==28758==    by 0xA79F1B: zend_activate_modules (zend_API.c:2537)
 
  ==28758==    by 0x9D31D3: php_request_startup (main.c:1673)
 
  ==28758==    by 0xB5909A: do_cli (php_cli.c:964)
 
  ==28758==    by 0xB5A423: main (php_cli.c:1381)
 
  也抓到了。
 
  Note
 
  Valgrind确实可以捕获所有内容。巨大的进程内存映射中某个地方的每一个被遗忘的小字节都会被valgrind的眼睛报告。您无法通过。

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读