使用超过 128M 时,PHP 出现分段错误

使用超过 128M 时,PHP 出现分段错误

我安装了 SugarCRM。它占用大量内存,这是需要单独处理的问题。同时,任何试图使用超过 128M 内存的页面都会导致 Apache (mod_php) 进程因分段错误而停止:

[notice] child pid 6852 exit signal Segmentation fault (11)

如果我将 PHP 内存限制设置为 128M,那么我永远不会收到信号 11;我只会收到正常的 PHP 错误,告诉我它无法分配更多内存。如果我将 PHP 内存限制设置为大于 128M(即使只是稍微大于 128M),那么任何占用该内存的进程都会导致分段错误,并给用户带来白屏/连接中断。

我在带有 Atomic 存储库的 CentOS 6.2 服务器上使用 PHP 5.3.21。这是一台生产服务器,因此不存在编译器,因此无法重新编译 Apache 进程来执行核心转储。

我们安装了 APC 3.1.13,有些网站需要它。我认为我的 SugarCRM 网站已禁用它。

我不确定诊断此问题还需要哪些其他详细信息?如果这里有人遇到过类似情况,我希望有一些显而易见的事情可以参考。如果内存使用量超过 128M,为什么会导致崩溃?

编辑:

情节变得复杂起来。此测试脚本运行,将 memory_limit 设置为 256M,直到 PHP 进程在 256M 左右耗尽内存。它不会导致分段错误;它运行并正常终止:

<?php phpinfo();

$array = array();

while (true) {
    $array[] = str_pad('', 1024*512, '0');
    echo " " . memory_get_usage();
}

因此,我们归结为 SugarCRM 所做的某件事(一个普通的 PHP/MySQL 应用程序)导致了分段错误,但只有当 memory_limit 设置为超过 128MBytes 并且达到的页面超过 128MBytes 阈值时才会发生。缩小范围将非常棘手。它是由应用程序中的一行特定的 PHP 代码或构造引起的,还是由应用程序碰巧做的一系列事情(例如,执行触发垃圾收集器开始整理的操作,或取消设置打开数据库连接的对象,或我能想到的所有类似的事情)导致 PHP 错误的结果,尚不清楚。

如果这是一个服务器问题,我不会感到惊讶,也许可以通过编程解决方法解决。

编辑2:

我现在可以轻松地重现分段错误:

<?php 
function test1() {
    static $instance = 0;
    $instance += 1;
    echo " $instance ";
    test1();
}
test1();

执行此类操作时可能会出现段错误。我个人希望 PHP 能够更好地处理该问题,但这可能对 PHP 来说是正常的吗?只要将 memory_limit 设置为 128M,它似乎就能很好地处理。当我将其设置为 256M 时,它反而会出现段错误。

通过逐步跟踪应用程序的执行,它似乎在写入其初始缓存文件时进入了递归循环(SugarCRM 进行了大量缓存)。这很难理解,但我怀疑这是由于缺乏错误处理造成的 - 它写入一个文件,然后只是期望文件在那里,而不检查 fopen() 的结果。我们正在运行 SELinux,我现在想知道这是否会造成阻碍 - 它在其他应用程序中肯定存在,其中 PHP 的 is_writeable() 说“好的,您可以在此处写入文件”,但这样做时,SELinux 启动并说,“你绝对不会写入文件在此处”。SugarCRM 检查第一个问题,然后并不总是检查它是否真的成功。

所以 - 我估计现在可以将其视为编程问题了?在我看来,这仍然是服务器和 PHP 之间不能很好地协同工作的问题,但 SugarCRM 中适当的错误修复应该可以解决这个问题。

答案1

这是我目前为止得到的最接近的结果,也可能是我目前能得到的最接近的结果:

  1. SugarCRM 没有正确地对其文件写入命令进行错误检查,因此有时无法意识到文件尚未写入。

  2. SugarCRM 在首次运行构建其运行时文件时会写入大量缓存文件。

  3. 在构建这些缓存文件时,一些不正确的权限导致某些文件无法正确写入。

  4. 丢失的文件使 SugarCRM 陷入无限递归循环,缓存写入方法以递归方式调用自身。

  5. 如果 PHP 的 memory_limit 设置为大于 128M,它不会报告进程内存不足,而是会报告分段错误。如果低于 128M,PHP 进程会更干净地被终止。我只能假设这是 PHP 错误,或者是插件(而不是 APC)中的错误。我不知道 128M 值从何而来。

我通过重新安装 SugarCRM 修复了这个问题,将所有文件和目录设置为 777,然后它就可以正常工作了。现在需要重新设置权限,直到我找到问题所在。SugarCRM(社区版)的票证会很有用,PHP 的票证也会很有用(尽管我预计我无法向他们提供他们必然会要求的核心转储,所以这可能是一条死路)。

谢谢大家的建议。我希望这对其他人有用。

答案2

摆脱 APC,用它的替代品 eAccelerator 或 XCache 来代替。多年来,它一直是我生产环境中类似神秘崩溃的根源,而 APC 消失后,这些崩溃都消失了。

相关内容