【问题标题】:Solving PHP memory leaks解决 PHP 内存泄漏
【发布时间】:2013-09-02 17:10:26
【问题描述】:

我有一个运行无限长的 PHP 脚本(无限主事件循环),处理来自 Twitter 的传入推文流并将它们存储到 MySQL。但是,我似乎无法控制它的内存使用。我找到了 3 种测量内存使用情况的方法:

  • memory_get_usage() - 报告大约 4.0 MB
  • memory_get_usage(true) - 报告大约 7.5 MB
  • exec("ps -o rss -p " . getmypid(), $memOutput); - 报告一个线性增加的数字,在 60 分钟或更短的时间内迅速增长到数百 MB,并继续消耗内存,直到脚本被强制终止。

我的问题:

1) 这三种措施之间的实际区别是什么?

但主要是:

2)如果前两个相对恒定,但第三种方法就这样失控了,那是什么意思?

FWIW,我正在使用 PHP 5.3 和 Zend Framework 1.x 以及很多 Zend_Db 活动。脚本在 CLI SAPI 下运行。 Zend_Db_Profiler 没有被使用。我还有第二个无限运行的脚本,它根本不使用数据库,并且内存使用量是恒定的。所以它似乎与数据库相关,可能是我的 PHP 设置正在使用的 MySQL 扩展,或者可能是 Zend_Db。我在自己的代码中非常努力地避免不小心缓存对象,尽管我没有使用 Zend 的代码本身这样做。

我尝试让我的脚本调用gc_enable(),并定期运行gc_collect_cycles(),但这没有帮助。

有什么想法吗?

编辑我打算尽快分析此代码,但同时我注意到即使我的脚本不接触数据库也泄漏记忆。但他们这样做的速度要慢得多,只有在比较几天的内存使用情况时才会显现出来。

【问题讨论】:

  • 在不再需要对象后,您已经采取了哪些步骤来回收内存?
  • 首先,我尽可能避免使用对象,方法是使用数组暂时存储我的数据。但是对于对象(例如 Zend_Db 返回的表行),我没有做任何特别的事情来回收它们的内存。我的理解是,当它们超出范围时(即方法结束时),并且不再保留对这些对象的引用时,它们就有资格通过 PHP 的垃圾收集进行回收。我没有保留任何参考资料。但我意识到 Zend_Db 可能是。

标签: php mysql zend-framework memory-leaks


【解决方案1】:

好吧,我无法在这里指出确切的答案,因为您需要自己进行分析。从您所说的看来,它似乎指向 Zend 的 DB 层,但是除非您对此进行分析,否则您无法确定。 ;)

在 UNIX/Linux 上(我希望您以正确的方式运行 PHP - UNIX/Linux 方式:D)有一些非常有用的工具可以在 系统级别 分析此类应用程序并检查PHP 应用程序中的实例化和内存消耗。 您可以使用Valgrind 获取一些信息,例如:

valgrind --tool=callgrind --dump-instr=yes -v --instr-atstart=no /usr/sbin/apache2 -X

请注意,Valgrind 是 suite of tools,这里我们使用的是“callgrind”工具 - 它

提供 Cachegrind 提供的所有信息,以及有关调用图的额外信息

这将创建一个callgrind.out 文件或一组我不记得的文件。 无论如何,您现在可以使用Kcachegrind 来可视化收集到的信息:

kcachegrind callgrind.out

您将看不到调用的可视化以及应用的某个部分使用的内存百分比。就像是:

您还可以尝试使用 Valgrind 套件中的其他一些工具,例如 Memcheck 来查看

所有内存的读写和对 malloc/new/free/delete 的调用

我在尝试分析我的 Linux 服务器时首次了解了 Valgrind。然后我研究了一下,结果发现它是一个非常好的分析 PHP 应用程序的工具......有a very good talk on this here。我使用了那里的一些例子。看看吧!

在你分析你的应用程序之后,请回来提供关于它是什么,或者你看到了什么等等的信息。我会很有趣地分析这个。希望这有帮助。 ;)

编辑: 我现在记得我错过了一些东西。 :D 你也可以尝试使用APD,这是一个zend扩展和could also provide useful information。我没有亲自使用过,但是网上有一些很好的例子。

另一个选项是Xhprof - 层次分析器。您可以将其用于gather different metrics。最后应该使用这些工具的组合。如何以及为什么取决于您。

【讨论】:

  • 感谢鲍里斯拉夫的指点。我还没有机会尝试它们,但是当我有机会时我会尝试。同时,我重写了我的脚本,因此与数据库相关的部分被称为单独的短期进程。这有效地解决了内存问题。
  • 我仍然很困惑为什么 PHP 的用户级内存使用函数显示稳定和可预测的值,而只有外部进程显示的内存使用情况(例如,命令行上的 ps)是什么手。这让我觉得它可能根本不是用户级 PHP 代码,但可能是 PHP 或我正在使用的某些扩展的低级问题。使用您提到的工具分析代码会非常有趣。
  • @curtisdf 是的,确实。描述它会很有趣。之后你愿意分享数据吗?无论如何,它不会包含任何代码。它也可能真的是一些外部实体。无论如何,PHP 是一种脚本语言,由于其设计,长时间运行的脚本一直是个问题。要尝试的其他事情之一是“异步 PHP”-react as an example。它可能是基于事件的长时间运行脚本的解决方案。
  • 我很乐意在此处发布我的发现,尽管由于现在已经避免了这个问题并且我有很多事情要做,我不确定什么时候可以解决。希望在接下来的几天或即将到来的周末内。
猜你喜欢
  • 2015-06-28
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 2011-08-14
  • 2010-12-11
  • 2018-04-11
相关资源
最近更新 更多