一个假设性的问题供大家思考...
我最近回答了另一个关于 PHP 脚本出现段错误的问题,它让我想起了我一直想知道的事情,所以让我们看看是否有人可以阐明它。
考虑以下:
<?php
function segfault ($i = 1) {
echo "$i\n";
segfault($i + 1);
}
segfault();
?>
显然,这个(无用的)函数无限循环。最终,将耗尽内存,因为对该函数的每次调用都会在前一个调用完成之前执行。有点像没有分叉的叉子炸弹。
但是......最终,在 POSIX 平台上,脚本将因 SIGSEGV 而终止(它也会在 Windows 上终止,但更优雅 - 就我极其有限的低级调试技能而言)。循环数量取决于系统配置(分配给 PHP、32 位/64 位等的内存)和操作系统,但我真正的问题是 - 为什么会发生段错误?
- 这就是 PHP 处理“内存不足”错误的方式吗?当然必须有一种更优雅的方式来处理这个问题吗?
- 这是 Zend 引擎中的错误吗?
- 有什么方法可以在 PHP 脚本中更优雅地控制或处理这个问题吗?
- 是否有任何设置通常控制函数中可以进行的最大递归调用次数?
如果使用 XDebug,则存在最大函数嵌套深度,该深度由ini设置 http://xdebug.org/docs/all_settings#max_nesting_level:
$foo = function() use (&$foo) {
$foo();
};
$foo();
产生以下错误:
致命错误:已达到最大函数嵌套级别“100”,正在中止!
恕我直言,这是比段错误更好的选择,因为它只杀死当前脚本,而不是整个过程。
有这是几年前(2006 年)的内部清单。他的评论是:
到目前为止,还没有人提出无限循环问题的解决方案
将满足这些条件:
- 没有误报(即好的代码总是有效)
- 执行速度不会减慢
- 适用于任何堆栈大小
因此,这个问题仍然没有解决。
现在,#1 实际上是不可能解决的,因为停止问题 http://en.wikipedia.org/wiki/Halting_problem。如果您保留堆栈深度的计数器,#2 就很简单了(因为您只是检查堆栈推送时递增的堆栈级别)。
最后,#3 是一个更难解决的问题。考虑到某些操作系统将以非连续的方式分配堆栈空间,不可能以 100% 的准确度实现,因为不可能可移植地获取堆栈大小或使用情况(对于特定平台,可能或甚至很容易,但一般而言并非如此)。
相反,PHP 应该从 XDebug 和其他语言(Python 等)获取提示并创建可配置的嵌套级别(Python 是set to http://docs.python.org/library/sys.html#sys.setrecursionlimit默认1000)....
或者,或者捕获堆栈上的内存分配错误,以在发生之前检查段错误并将其转换为RecursionLimitException
以便您能够康复......
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)