问题描述
一个假设性的问题供大家思考......
A hypothetical question for you all to chew on...
我最近回答了关于 SO 的另一个问题,其中 PHP 脚本出现了段错误,这让我想起了我一直想知道的事情,所以让我们看看是否有人可以对此有所了解.
I recently answered another question on SO where a PHP script was segfaulting, and it reminded me of something I have always wondered, so let's see if anyone can shed any light on it.
考虑以下几点:
<?php
function segfault ($i = 1) {
echo "$i
";
segfault($i + 1);
}
segfault();
?>
显然,这个(无用的)函数无限循环.最终,将耗尽内存,因为对函数的每次调用都会在前一次调用完成之前执行.有点像没有分叉的分叉炸弹.
Obviously, this (useless) function loops infinitely. And eventually, will run out of memory because each call to the function executes before the previous one has finished. Sort of like a fork bomb without the forking.
但是...最终,在 POSIX 平台上,脚本会随着 SIGSEGV 而死(它也会在 Windows 上死掉,但更优雅 - 就我极其有限的低级调试技能而言).循环的数量取决于系统配置(分配给 PHP、32 位/64 位等的内存)和操作系统,但我真正的问题是 - 为什么会发生段错误?
But... eventually, on POSIX platforms, the script will die with SIGSEGV (it also dies on Windows, but more gracefully - so far as my extremely limited low-level debugging skills can tell). The number of loops varies depending on the system configuration (memory allocated to PHP, 32bit/64bit, etc etc) and the OS but my real question is - why does it happen with a segfault?
- 这仅仅是 PHP 处理内存不足"错误的方式吗?肯定有更优雅的方式来处理这个问题吗?
- 这是 Zend 引擎中的错误吗?
- 有什么方法可以在 PHP 脚本中更优雅地控制或处理?
- 是否有任何设置可以控制函数中递归调用的最大数量?
推荐答案
如果你使用 XDebug,有一个最大的函数嵌套深度由 ini设置:
If you use XDebug, there is a maximum function nesting depth which is controlled by an ini setting:
$foo = function() use (&$foo) {
$foo();
};
$foo();
产生以下错误:
致命错误:达到100"的最大函数嵌套级别,正在中止!
这个恕我直言是一个比段错误更好的选择,因为它只杀死当前脚本,而不是整个过程.
This IMHO is a far better alternative than a segfault, since it only kills the current script, not the whole process.
几年前有这个帖子在内部列表中(2006 年).他的评论是:
There is this thread that was on the internals list a few years ago (2006). His comments are:
到目前为止,没有人提出解决无限循环问题的方法将满足这些条件:
- 没有误报(即好的代码总是有效的)
- 执行速度不会减慢
- 适用于任何堆栈大小
因此,这个问题仍未解决.
Thus, this problem remains unsloved.
现在,由于停机问题,#1 几乎无法解决.如果您保留堆栈深度计数器,#2 是微不足道的(因为您只是检查堆栈推送时增加的堆栈级别).
Now, #1 is quite literally impossible to solve due to the halting problem. #2 is trivial if you keep a counter of stack depth (since you're just checking the incremented stack level on stack push).
最后,#3 是一个更难解决的问题.考虑到某些操作系统会以非连续方式分配堆栈空间,因此不可能以 100% 的准确度实现,因为不可能便携地获取堆栈大小或使用情况(对于特定平台,它可能是可能的或甚至很容易,但不是一般的).
Finally, #3 Is a much harder problem to solve. Considering that some operating systems will allocate stack space in a non-contiguous manner, it's not going to be possible to implement with 100% accuracy, since it's impossible to portably get the stack size or usage (for a specific platform it may be possible or even easy, but not in general).
相反,PHP 应该从 XDebug 和其他语言(Python 等)获得提示,并制作可配置的嵌套级别(Python 是 默认设置为 1000)....
Instead, PHP should take the hint from XDebug and other languages (Python, etc) and make a configurable nesting level (Python's is set to 1000 by default)....
要么这样,要么在堆栈上捕获内存分配错误以在段错误发生之前检查它并将其转换为 RecursionLimitException
以便您可以恢复......
Either that, or trap memory allocation errors on the stack to check for the segfault before it happens and convert that into a RecursionLimitException
so that you may be able to recover....
这篇关于为什么 PHP 中的无限递归函数会导致段错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!