我目前正在调试一个脚本,它经常遇到OutOfMemory异常。它作为cronjob运行,并且通常运行良好,但是当cronjob由于某种原因一段时间没有运行时,脚本必须处理太多排队的元素,就会遇到OutOfMemory异常。
通过检查代码,我无法发现问题所在。我认为其中一个迭代函数调用可能会泄漏内存,但我不确定哪个函数和在哪里。 当OutOfMemory异常发生时,有没有选项可以让PHP转储堆?我可能能够从那里找到问题(最有可能)。
我目前正在调试一个脚本,它经常遇到OutOfMemory异常。它作为cronjob运行,并且通常运行良好,但是当cronjob由于某种原因一段时间没有运行时,脚本必须处理太多排队的元素,就会遇到OutOfMemory异常。
通过检查代码,我无法发现问题所在。我认为其中一个迭代函数调用可能会泄漏内存,但我不确定哪个函数和在哪里。 当OutOfMemory异常发生时,有没有选项可以让PHP转储堆?我可能能够从那里找到问题(最有可能)。
虽然我没有找到“异常时转储堆”的选项,但我找到了get_defined_vars()
,如果从全局范围调用,它基本上就是一个堆转储。使用它,我能够看到我的内存中仍有数百(实际上是数千)个仍在引用的数据库行挂起。这是由于某个问题函数中未释放的mysql结果资源导致的泄漏。我找到了并修复了它。现在运行良好。
get_defined_vars()
转储为 json 文件。然后通过 jq .
运行这些文件以获取类似格式的输出。一旦你做到了这一点,就可以比较这两个文件,并且很可能会发现增加了某些内容。根据这些信息,我回到了上一个转储文件并找到了新增的项目。 - Mat Schaffer最简单的方法是,在脚本可能出错的部分使用try-catch块,并在catch部分中转储堆栈。问题可能是机器无法响应,因为内存已满并终止。我不知道丢弃一些变量是否有助于释放一些内存以输出一些数据。
编辑:为此,请使用php函数debug-backtrace。这将给您提供一个堆栈跟踪。因此,如果机器仍在运行,则很可能能够找到错误。
我从未见过PHP提供本地支持,但可能存在其他一些选择:
尝试:https://github.com/mcfunley/php-heap/blob/master/php-heap.py
也有可能编写扩展来实现相同的功能。
这是我能够快速用PHP编写的“堆转储”的最佳版本。我获取定义的变量和函数,然后按其序列化长度进行排序。序列化长度并不是获取变量大小的100%可靠方法,但它相当不错,并且通常有助于确定哪些对象是您的内存占用量大的对象:
$memmap = array_map(function($var) { return strlen(serialize($var)); },
array_merge(get_defined_functions(), get_defined_vars()));
arsort($memmap);
var_dump($memmap);
如果您希望结果更详细或递归遍历定义的变量,则可能需要稍微调整回调函数。
只需在处理对象时逐个读取,而不是将所有对象一起加载到内存中?
我在使用simpleXML时遇到了很多问题和内存泄漏。这些问题非常难以跟踪......花费我好几天时间才弄清楚是simpleXML导致的并解决了它们。 据我所知,您可以编程设置OOM的句柄:)
此外,PHP用于显示内存信息的函数无法检测到内存泄漏,我有一些脚本占用了约1GB的内存,但PHP的函数仅报告使用了100MB:)