2010-10-25 79 views
3

我目前正在调试一个不断运行到OutOfMemory异常的脚本。它作为一个cronjob运行并且通常运行良好,但是当cronjob没有运行一段时间(无论出于何种原因)时,脚本必须处理排队的许多元素,并且会运行到OutOfMemory异常。在OutOfMemory异常上有PHP转储堆

从检查代码我无法发现问题。我相信其中一个迭代函数调用可能会泄漏内存,但我不确定哪一个在哪里。 当出现OutOfMemory异常时,是否有一个让PHP转储堆的选项?我可能会从那里发现问题(很可能)。

+0

http://de3.php.net/manual/en/function.memory-get-peak-usage.php – teemitzitrone 2010-10-25 12:14:18

+0

我知道峰值的使用情况,这正是我脚本崩溃时的内存限制。否则我不知道这对我有什么帮助。 – 2010-10-25 12:19:45

回答

5

虽然我无法找到“转储堆的异常”选项,但我确实发现get_defined_vars()这基本上是一个堆转储,如果从全局范围调用。使用这个,我能够看到有数百个(实际上有数千个)被引用的数据库行在我的记忆中。这是由于在臭名昭着的导致泄漏的函数中没有释放mysql结果资源。我找到并修复了它。它现在运行良好。

+0

你是如何使用get_defined_vars()实际查明问题的?你刚刚运行一段时间的脚本,然后让它转储,或者当脚本运行到内存泄漏时,是否有办法触发调用该函数? – 2010-12-29 23:58:31

+1

我实现了一个迭代计数器,它可以在崩溃前向我显示迭代的大概数量,在我的情况下,它在20000到22000次迭代之间。然后我运行脚本并在第18000次迭代中使用get_defined_vars来转储堆。在我的情况下,然后很明显是什么混乱的记忆。 – 2011-01-08 11:33:12

+0

为了让事情更清楚一点,我为每次迭代都将'get_defined_vars()'作为json转储到一个文件中。然后通过'jq .'运行这些文件,以使它们具有相似的格式。一旦你有,你可以区分这两个文件,并可能看到一些添加。有了这些信息,我回到了最后一个转储文件,并找到了添加的项目。 – 2016-02-10 06:55:01

1

那么,最简​​单的方法就是在脚本的可能发生错误的那部分周围使用try-catch块,并且您将不得不将堆栈转储到catch部分。问题可能是机器人无法响应,导致内存已满并终止。我不知道是否有助于放弃一些变量来释放一些内存来输出一些数据。

编辑:为此,使用php函数debug-backtrace。这会给你一个堆栈跟踪。所以如果机器还在运转,发现错误将很有可能。

+0

我认为他的问题是关于如何*转储堆。 – 2010-10-25 12:01:57

+0

请原谅我,但我如何在抓取部分“转储堆”?我当然不是在谈论SplHeap,而是PHP脚本的内存堆。 – 2010-10-25 12:03:14

+0

寻找记忆(http://php.net/manual-lookup.php?pattern=memory&src=)或堆(http://php.net/manual-lookup.php?pattern=heap&src=)不会产生任何有希望的结果(OT:我如何在评论中嵌入链接,或者我不能?) – 2010-10-25 12:16:45

0

只是不把所有对象加载到内存中,而是尽可能地读取它们?

+0

这是脚本似乎从目测检查代码所做的事情。正如我所说,我怀疑有内存泄漏。也许是因为循环引用(这是PHP 5.0),但是通过阅读它们线来调试成千上万行代码可能会发现问题只是浪费时间。 – 2010-10-25 12:15:44

+0

你需要在PHP中创造一个内存泄漏,除非你只需要一个数组并放入数据(可能使用一些奇怪的联想键)而不需要再次删除它...... – joni 2010-10-25 12:37:15

+0

你的意思与创建递归关联一样有创意吗?例如,他们会在5.3之前创建内存泄漏,因为gc无法检测到它们。由于我正在调试的代码不是我的,我不知道可能会发生什么病。 – 2010-10-25 14:24:02

0

我有很多simpleXML和内存泄漏的问题。他们很难追踪到......花了我好几天的时间来弄清楚那个简单的XML引起了什么,然后解决了它们。 据我知道你C和编程设置OOM :)

另外一个处理,PHP的显示内存信息功能无法检测内存泄漏,我不得不脚本吃起来〜1GB内存,但PHP的功能只报100Mb使用:)

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);

您可能需要调整的回调函数如果你希望你的结果更加冗长,或者通过定义的变量进行递归,那么有点儿。