我目前正在调试一个经常遇到内存不足异常的脚本。它作为 cronjob 运行并且通常运行良好,但是当 cronjob 一段时间没有运行时(无论出于何种原因),脚本必须处理许多排队的元素,并且会遇到 OutOfMemory 异常。
通过检查代码我无法发现问题。我相信其中一个迭代函数调用可能会泄漏内存,但我不确定是哪一个以及在哪里。
当发生 OutOfMemory 异常时,是否有一个选项可以让 PHP 转储堆?我也许能够从那里发现问题(最有可能)。
I am currently debugging a script that constantly runs into OutOfMemory exceptions. It is run as a cronjob and usually runs fine, but when the cronjob wasn't run for a while (for whatever reason) the script has to handle to many elements that queued up and will run into a OutOfMemory exception.
From examining the code I was not able to spot the problem. I believe one of the iterative function calls might leak memory, but I am not sure which one and where.
Is there an option to get PHP to dump the heap, when an OutOfMemory exception occurs? I might be able to spot the problem from there (most likely).
发布评论
评论(6)
虽然我无法找到“异常时转储堆”选项,但我确实找到了 get_define_vars() ,如果从全局范围调用,它基本上是一个堆转储。使用这个,我能够看到数百(实际上是数千)仍然引用的数据库行挂在我的记忆中。这是由于臭名昭著的函数中某处未释放 mysql 结果资源导致了泄漏。我找到了它并修复了它。现在运行良好。
While I was not able to find a "dump heap on Exception" option, I did find
get_defined_vars()
which is basically a heap dump if called from a global scope. Using this I was able to see that there where hundreds (actually thousands) of still referenced database rows hanging around in my memory. This was due to a not freed mysql result resource somewhere in the infamous function that caused the leak. I found it and fixed it. It runs well now.嗯,最简单的方法是在脚本中可能发生错误的部分使用 try-catch 块,并且您必须将堆栈转储到 catch 部分。问题可能是机器将无法做出反应,因为内存已满并终止。我不知道丢弃一些变量以释放一些内存来输出一些数据是否有帮助。
编辑:为此目的,请使用 php 函数 debug-回溯。这将为您提供堆栈跟踪。因此,如果机器仍在运行,则很有可能发现错误。
Well, easiest approach would be to use a try-catch block around that part of your script where the error possibly occurs and you will have to dump the stack in the catch part. The problem might be that the machine won't be able to react cause the memory is full and it terminates. I do not know if it helps to discard some variables to free up some memory to output some data.
EDIT: For this purpose use the php function debug-backtrace. This will give you a stack trace. So finding the error will be much likely in case the machine is still up.
只是不要将所有对象一起加载到内存中,而是在处理它们时读取它们?
Just do not load all objects together to memory, but read-as-you-process-them?
我在 simpleXML 和内存泄漏方面遇到了很多问题。追踪它们是一件很痛苦的事情……我花了几天时间才弄清楚是 simpleXML 造成的,然后修复了它们。
据我所知,您可以通过编程方式设置 OOM 的句柄:)
另外,PHP 用于显示内存信息的函数无法检测内存泄漏,我的脚本消耗了约 1Gb 的内存,但 PHP 的函数报告仅使用了 100Mb:)
I've had lots of problems with simpleXML and memory leaks. They are a pain in the are to track down... took me days to figure out that simpleXML was causing then and then fix them.
As far as i know you cand programatically set a handled for OOM:)
Also, PHP's functions for displaying memory info fails to detect the memory leaks, i had scripts eating up ~1Gb of ram, but PHP's functions reported only 100Mb used:)
这是我能够用 PHP 快速编写的“堆转储”。我获取定义的变量和函数,然后按它们的序列化长度进行排序。序列化长度并不是获取变量大小的 100% 可靠方法,但它非常好,并且通常可用于确定哪些对象占用内存:
$memmap = array_map(function($var) { return strlen(序列化($var));
array_merge(get_define_functions(), get_define_vars()));
排序($memmap);
var_dump($memmap);
如果您希望结果更加详细,或者通过定义的变量进行递归,您可能需要稍微调整回调函数。
This is as good of a 'heap dump' as I'm able to quickly write in PHP. I take the defined variables and functions, then sort by their serialized length. Serialized length isn't a 100% reliable method for getting a variable's size, but it's pretty good, and generally useful for determining which objects are your memory hogs:
$memmap = array_map(function($var) { return strlen(serialize($var)); },
array_merge(get_defined_functions(), get_defined_vars()));
arsort($memmap);
var_dump($memmap);
You may want to tweak the callback function a bit if you'd like your results to be more verbose, or to recurse through the defined variables.
我从未见过 PHP 为此提供本机工具,但可能存在其他一些东西:
尝试: https://github.com/mcfunley/php-heap/blob/master/php-heap.py
也可以编写一个扩展来实现相同的目的。
I've never seen PHP provide a native facility for this but a few other things might exist:
Try: https://github.com/mcfunley/php-heap/blob/master/php-heap.py
It could also be possible to write an extension to achieve the same.