您知道从 PHP 致命错误中恢复的任何解决方案吗:“允许的内存大小...耗尽”
我有一个在出现致命错误时调用的关闭函数。该函数从中创建一个 ErrorException 并记录它。
问题是:当没有更多可用内存时,它无法记录错误(我通过 FirePHP 和 Zend Framework 登录 Firebug)。
那么我所说的“如何从中恢复”的意思是如何执行基本的错误日志,并让 Zend Framework 发送标头,以便将错误(在我的情况下在 Firebug 中)记录为任何其他错误?
谢谢
if((memory_get_usage() / 1024 /1024) < 70)
我只需将 memory_get_usage 除以 1024 的平方,将其与“正常”兆字节值“70”进行比较。
我在 for 循环中遇到了 php 的内存问题,并编写了这个简单的 if 语句来防止我的脚本引发致命错误。此外,我正在操作的服务器不允许我修改内存限制(在某些云产品(如 openshift 或大型 Web 主机(如 dreamhost))中经常出现这种情况。)我并没有真正注意到任何严重的性能下降(在 php 5.3 中,它处理此类函数的方式可能与 php 4.x 或 5.x 略有不同......无论如何,脚本给出致命错误的性能影响超过了函数调用可能强制的任何开销,并且还会阻止。一个消耗所有可用内存的失控脚本。
很多人可能会争论;哦嘿,你的软件没有优化。是的。你也许是对的;但对于复杂的数据集,在需要投入更多内存之前,您只能挤出有限的性能;在 ajax 流程中查找内存错误可能会非常令人沮丧;特别是当您不确定日志文件在哪里时。
此错误是致命错误 - 这意味着您无法从中恢复。 如果 PHP 达到了内存限制,它将无法分配更多内存来创建异常以及执行执行所需的任何其他内存。
还有另一种类型的错误 - “可捕获的致命错误”,顾名思义,可以在 try/catch 中捕获,但不幸的是内存大小分配不是其中之一。
自定义错误处理的常规方式是通过
set_error_handler
— 设置用户定义的错误处理函数
此功能的文档状态(强调我的):
以下错误类型无法使用用户定义的函数进行处理:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 以及调用 set_error_handler() 的文件中引发的大部分 E_STRICT。
所以,它不会经常起作用,但你可以尝试
从 PHP7 开始,错误和异常都是 Throwables,因此您可以尝试/捕获它们:
这对我来说效果很好:
try {
ini_set('memory_limit', (ini_get('memory_limit')+1).'M');
} catch(Exception $e) {}
这假设您的内存限制采用格式
123M
。
PHP 错误默认发送到您的 apache 错误日志
/path/to/apache/logs/error.log
,您可以在那里看到它。
有一个未经测试的技巧的想法,我很高兴知道它是否有帮助。在第一次注册关闭函数时分配一些全局变量,并在第一次执行关闭函数的代码时释放它。然后您可能有足够的内存来创建 Exception 对象。让我知道它是否有效,并请在此处发布代码。
我能想到的是,当您进行内存密集型操作时,您会定期手动查询
memory_get_usage()
(例如每次循环迭代),并在超过某些故障安全值时转储标头/错误,即低于脚本限制。它会大大减慢你的脚本速度,但至少你会得到一些回报。
或者,您可能无法执行此操作,通过使用 exec 从基于 Web 的内容中调用基于 CLI 的脚本来运行内存密集型内容。 CLI 部分可能会崩溃,但 Web 部分将能够报告它。
我刚刚发现,对于我的情况,如果用大 int 键填充数组(例如 83253143401),请将它们转换为 String。否则 PHP 将初始化第一个元素为 83253143400 的空数组,甚至 2Gb 内存也不够。