检测并分析PHP扩展的内存泄露

Posted by LB on Tue, Jul 31, 2018

1. 背景描述

基于C/C++开发的程序,内存管理是很大程度上的工作,我们在这篇文章里来给大家讲解一下如何监控程序体可能存在的内存泄露。

工欲善其事必先利其器,这里选择使用 Valgrind 工作来进行内存监控。http://valgrind.org/

2. Valgrind工具安装

1  git clone git://sourceware.org/git/valgrind.git
2  ./autogen.sh
3  ./configure --prefix=/usr/local/valgrind
4  make
5  make install

3. 测试命令样例

1valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes php PulseFlow.php

4. 一次针对PHP扩展的内存泄露检测过程

针对已经开源的 PulseFLow 插件,今天我们将进行相关的内存泄露检测,由于我们是对PHP扩展进行泄露检查,所以:

第一步,需要给PHP打开debug 编译参数,相关的编译参数如 ./configure --enable-debug

第二步,我们需要关闭zend 内存管理 ,添加相关的环境变量 export USE_ZEND_ALLOC=0 export ZEND_DONT_UNLOAD_MODULES=1

第三步,我们执行相关命令

1ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0 valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes php PulseFlow.php

第四步,查看报告,获得总体报告如下

1==20296== LEAK SUMMARY:
2==20296==    definitely lost: 0 bytes in 0 blocks
3==20296==    indirectly lost: 0 bytes in 0 blocks
4==20296==      possibly lost: 0 bytes in 0 blocks
5==20296==    still reachable: 75,936 bytes in 29 blocks
6==20296==         suppressed: 0 bytes in 0 blocks

5. 相关报告参数

  1. definitely lost :确认泄露,程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。

  2. indirectly lost:不直接泄露,当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与"definitely lost"一起出现,只要修复"definitely lost"即可。

  3. possibly lost:可能泄露,大多数情况下应视为与"definitely lost"一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。例子可参考我的例程。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存的起始地址,但可以访问其中的某一部分数据,则会报这个错误。

  4. still reachable:现在仍能访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源,因此笔者建议修复它。如果程序是崩溃(如访问非法的地址而崩溃)而非正常结束的,则应当暂时忽略它,先修复导致程序崩溃的错误,然后重新检测。(此参数可能和相关运行环境有关,比如当前的PHP运行环境,不一定适用于 扩展 环境)

  5. suppressed:已被解决。出现了内存泄露但系统自动处理了,可以无视这类错误。