一个假设的问题,你们都要咀嚼......
我最近在SO上回答了另一个问题,其中一个PHP脚本是segfaulting,它让我想起了我一直想知道的东西,所以让我们看看是否有人可以对它有所了解。
请考虑以下事项:
<?php
function segfault ($i = 1) {
echo "$i\n";
segfault($i + 1);
}
segfault();
?>
显然,这个(无用的)函数无限循环。最终,由于每个对函数的调用都是在前一个调用完成之前执行的,因此会耗尽内存。有点像没有分叉的叉炸弹。
但是......最终,在POSIX平台上,脚本会死于SIGSEGV(它也会死在Windows上,但更优雅 - 只要我极其有限的低级调试技能可以说明)。循环次数取决于系统配置(分配给PHP的内存,32位/ 64位等)和操作系统,但我真正的问题是 - 为什么会发生段错误?
答案 0 :(得分:24)
答案 1 :(得分:4)
我可能完全错了,因为我的测试相当简短。似乎Php只会在内存不足时出错(并且可能会尝试访问无效的地址)。如果内存限制设置且足够低,则会预先出现内存不足错误。否则,代码段出错并由操作系统处理。
不能说这是否是一个bug,但是可能不允许脚本失控。
请参阅下面的脚本。无论选项如何,行为几乎相同。没有内存限制,它也会在我的计算机被杀之前严重减慢它。
<?php
$opts = getopt('ilrv');
$type = null;
//iterative
if (isset($opts['i'])) {
$type = 'i';
}
//recursive
else if (isset($opts['r'])) {
$type = 'r';
}
if (isset($opts['i']) && isset($opts['r'])) {
}
if (isset($opts['l'])) {
ini_set('memory_limit', '64M');
}
define('VERBOSE', isset($opts['v']));
function print_memory_usage() {
if (VERBOSE) {
echo memory_get_usage() . "\n";
}
}
switch ($type) {
case 'r':
function segf() {
print_memory_usage();
segf();
}
segf();
break;
case 'i':
$a = array();
for ($x = 0; $x >= 0; $x++) {
print_memory_usage();
$a[] = $x;
}
break;
default:
die("Usage: " . __FILE__ . " <-i-or--r> [-l]\n");
break;
}
?>
答案 2 :(得分:2)
对PHP实现一无所知,但在语言运行时中将页面未分配到堆栈的“顶部”并不常见,以便在堆栈溢出时发生段错误。通常这是在运行时内部处理的,并且堆栈被扩展或报告更优雅的错误,但是可能存在实现(以及其他情况)其中segfault被允许上升(或逃逸)。