我目前正在调试一个不断遇到 OutOfMemory 异常的脚本。它作为 cronjob 运行并且通常运行良好,但是当 cronjob 有一段时间没有运行(无论出于何种原因)时,脚本必须处理许多排队的元素,并且会遇到 OutOfMemory 异常。
通过检查代码,我无法发现问题。我相信其中一个迭代函数调用可能会泄漏内存,但我不确定是哪一个以及在哪里。当发生 OutOfMemory 异常时,是否可以选择让 PHP 转储堆?我也许可以从那里发现问题(很可能)。
我目前正在调试一个不断遇到 OutOfMemory 异常的脚本。它作为 cronjob 运行并且通常运行良好,但是当 cronjob 有一段时间没有运行(无论出于何种原因)时,脚本必须处理许多排队的元素,并且会遇到 OutOfMemory 异常。
通过检查代码,我无法发现问题。我相信其中一个迭代函数调用可能会泄漏内存,但我不确定是哪一个以及在哪里。当发生 OutOfMemory 异常时,是否可以选择让 PHP 转储堆?我也许可以从那里发现问题(很可能)。
虽然我无法找到“异常转储堆”选项,但我确实找到get_defined_vars()
了如果从全局范围调用基本上是堆转储。使用它,我能够看到数百(实际上数千)仍然引用的数据库行在我的记忆中徘徊。这是由于在导致泄漏的臭名昭著的函数中某处未释放 mysql 结果资源。我找到并修复了它。现在运行良好。
好吧,最简单的方法是在脚本中可能发生错误的那部分周围使用 try-catch 块,并且您必须将堆栈转储到 catch 部分。问题可能是机器无法做出反应,因为内存已满并终止。我不知道是否有助于丢弃一些变量以释放一些内存来输出一些数据。
编辑:为此目的使用 php 函数debug-backtrace。这将为您提供堆栈跟踪。因此,如果机器仍在运行,则很有可能找到错误。
只是不要将所有对象一起加载到内存中,而是在处理它们时读取它们?
我在 simpleXML 和内存泄漏方面遇到了很多问题。追踪它们是一件很痛苦的事……我花了几天时间才弄清楚simpleXML是当时造成的,然后修复它们。据我所知,您可以以编程方式为 OOM 设置一个处理:)
此外,PHP 用于显示内存信息的函数无法检测到内存泄漏,我的脚本占用了大约 1Gb 的内存,但 PHP 的函数报告仅使用了 100Mb :)
这与我能够用 PHP 快速编写的“堆转储”一样好。我采用定义的变量和函数,然后按它们的序列化长度排序。序列化长度不是获取变量大小的 100% 可靠的方法,但它非常好,并且通常可用于确定哪些对象是你的内存占用者:
$memmap = array_map(function($var) { return strlen(serialize($var)); },
array_merge(get_defined_functions(), get_defined_vars()));
arsort($memmap);
var_dump($memmap);
如果您希望结果更详细,或者通过定义的变量进行递归,您可能需要稍微调整回调函数。
我从未见过 PHP 为此提供本机工具,但可能存在其他一些东西:
试试:https ://github.com/mcfunley/php-heap/blob/master/php-heap.py
也可以编写一个扩展来实现相同的目的。