本文共 4598 字,大约阅读时间需要 15 分钟。
php - 诊断内存泄漏 - 允许#bytes的内存大小耗尽
我已经遇到了可怕的错误消息,可能通过艰苦的努力,PHP已经耗尽了内存:
在第123行的file.php中,####字节的允许内存大小耗尽(尝试分配####字节)
增加限制
如果您知道自己正在做什么并希望增加限制,请参阅memory_limit:
ini_set('memory_limit', '16M');
ini_set('memory_limit', -1); // no limit
谨防! 你可能只是解决症状而不是问题!
诊断泄漏:
错误消息指向一条带有循环的行,我认为该循环正在泄漏或不必要地累积内存。 我在每次迭代结束时打印了$user语句,并且可以看到数字缓慢增长,直到达到限制:
foreach ($users as $user) {
$task = new Task;
$task->run($user);
unset($task); // Free the variable in an attempt to recover memory
print memory_get_usage(true); // increases over time
}
出于这个问题的目的,让我们假设可以想象的最糟糕的意大利面条代码隐藏在$user或Task中的全局范围内。
什么工具,PHP技巧或调试巫毒可以帮助我找到并解决问题?
Mike B asked 2019-08-22T15:25:47Z
13个解决方案
45 votes
PHP没有垃圾收集器。 它使用引用计数来管理内存。 因此,最常见的内存泄漏源是循环引用和全局变量。 如果您使用框架,那么您将需要大量代码才能找到它,我很害怕。 最简单的工具是选择性地将调用发送到memory_get_usage并将其缩小到代码泄漏的位置。 您还可以使用xdebug创建代码跟踪。 使用执行跟踪和show_mem_delta运行代码。
troelskn answered 2019-08-22T15:26:04Z
11 votes
php中有几个可能的内存泄漏点:
php本身
php扩展
你使用的PHP库
你的PHP代码
没有深度逆向工程或php源代码知识,很难找到并修复前3个。 对于最后一个,您可以使用二进制搜索内存泄漏代码和memory_get_usage
kingoleg answered 2019-08-22T15:27:34Z
8 votes
这是我们用来识别哪些脚本在我们的服务器上使用最多内存的技巧。
将以下代码段保存在文件中,例如,touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_log:
function strangecode_log_memory_usage()
{
$site = '' == getenv('SERVER_NAME') ? getenv('SCRIPT_FILENAME') : getenv('SERVER_NAME');
$url = $_SERVER['PHP_SELF'];
$current = memory_get_usage();
$peak = memory_get_peak_usage();
error_log("$site current: $current peak: $peak $url\n", 3, '/var/log/httpd/php_memory_log');
}
register_shutdown_function('strangecode_log_memory_usage');
通过在httpd.conf中添加以下内容来使用它:
php_admin_value auto_prepend_file /usr/local/lib/php/strangecode_log_memory_usage.inc.php
然后分析日志文件touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_log
在Web用户可以写入日志文件之前,您可能需要touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_log。
Quinn Comendant answered 2019-08-22T15:29:02Z
7 votes
我注意到在旧脚本中有一次PHP将维护" as" 即使在我的foreach循环之后,也在范围内变量。 例如,
foreach($users as $user){
$user->doSomething();
}
var_dump($user); // would output the data from the last $user
我不确定未来的PHP版本是否已修复此问题,因为我已经看过了。 如果是这种情况,你可以在doSomething()之后将unset($user)行从内存中清除它。因人而异。
patcoll answered 2019-08-22T15:29:40Z
6 votes
我最近在一个应用程序上遇到了这个问题,在我收集到的类似情况下。 一个在PHP的cli中运行的脚本,循环遍历多次迭代。 我的脚本依赖于几个底层库。 我怀疑某个特定的库是原因,我花了几个小时徒劳地试图在它的类中添加适当的破坏方法无济于事。 面对一个漫长的转换过程到一个不同的库(可能会遇到同样的问题)我想出了一个粗略的解决方案来解决我的问题。
在我的情况下,在linux cli上,我循环了一堆用户记录,并为每一个创建了我创建的几个类的新实例。 我决定尝试使用PHP的exec方法创建类的新实例,以便这些进程可以在"新线程"中运行。 这是我所指的一个非常基本的样本:
foreach ($ids as $id) {
$lines=array();
exec("php ./path/to/my/classes.php $id", $lines);
foreach ($lines as $line) { echo $line."\n"; } //display some output
}
显然这种方法有局限性,需要注意这种方法的危险,因为创建兔子工作很容易,但在极少数情况下,它可能有助于克服困难,直到找到更好的解决方案 ,就像我的情况一样。
Nate Flink answered 2019-08-22T15:30:32Z
6 votes
我遇到了同样的问题,我的解决方案是用常规替换foreach。 我不确定具体细节,但似乎foreach为对象创建了一个副本(或某种新的引用)。 使用常规for循环,您可以直接访问该项目。
Gunnar Lium answered 2019-08-22T15:31:05Z
3 votes
我最近注意到PHP 5.3 lambda函数在删除它们时会留下额外的内存。
for ($i = 0; $i < 1000; $i++)
{
//$log = new Log;
$log = function() { return new Log; };
//unset($log);
}
我不确定为什么,但即使在删除该函数后,每个lambda似乎还需要250个字节。
Xeoncross answered 2019-08-22T15:31:53Z
3 votes
我建议你查看php手册或添加gc_enable()函数来收集垃圾......这就是内存泄漏不会影响代码的运行方式。
PS:php有一个垃圾收集器gc_enable(),不带任何参数。
Kosgei answered 2019-08-22T15:32:37Z
2 votes
如果您在PHP函数为真后只对GC做了什么,那么您可以将循环内容包装在函数内作为变通方法/实验。
Bart van Heukelom answered 2019-08-22T15:33:06Z
2 votes
我遇到的一个大问题是使用create_function。 与lambda函数一样,它将生成的临时名称留在内存中。
内存泄漏的另一个原因(在Zend Framework的情况下)是Zend_Db_Profiler。如果在Zend Framework下运行脚本,请确保已禁用。例如,我在我的application.ini中有以下内容:
resources.db.profiler.enabled = true
resources.db.profiler.class = Zend_Db_Profiler_Firebug
在此之前运行大约25.000个查询+加载处理,使内存达到了一个不错的128Mb(我的最大内存限制)。
只需设置:
resources.db.profiler.enabled = false
它足以使其低于20 Mb
这个脚本在CLI中运行,但是它实例化了Zend_Application并运行了Bootstrap,所以它使用了&#34;开发&#34;配置。
它真的有助于使用xDebug分析运行脚本
Andy answered 2019-08-22T15:34:32Z
2 votes
我没有明确提到它,但xdebug在分析时间和内存方面做得很好(截至2.6)。 您可以获取它生成的信息并将其传递给您选择的gui前端:webgrind(仅限时间),kcachegrind,qcachegrind或其他,它会生成非常有用的调用树和图形,以便您找到各种困境的来源。
示例(qcachegrind):
SeanDowney answered 2019-08-22T15:35:13Z
1 votes
我对这次谈话有点迟,但我会与Zend Framework分享一些相关内容。
我安装了php 5.3.8(使用phpfarm)来处理使用php 5.2.9开发的ZF应用程序后出现内存泄漏问题。 我发现内存泄漏是在Apache的httpd.conf文件中触发的,在我的虚拟主机定义中,它说的是SetEnv APPLICATION_ENV "development".在注释掉这一行之后,内存泄漏就停止了。 我试图在我的php脚本中提出一个内联解决方法(主要是在主index.php文件中手动定义它)。
fronzee answered 2019-08-22T15:35:56Z
0 votes
我没有在这里看到它,但有一点可能有用,就是使用xdebug和xdebug_debug_zval(&#39; variableName&#39;)来查看引用计数。
我还可以提供一个php扩展的例子:Zend Server的Z-Ray。 如果启用了数据收集,则内存使用将在每次迭代时生成气球,就像垃圾收集已关闭一样。
HappyDude answered 2019-08-22T15:36:42Z
转载地址:https://blog.csdn.net/weixin_33520510/article/details/115159256 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!