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