【发布时间】:2014-01-07 06:16:25
【问题描述】:
这可能更适合服务器故障,但我想我会先在这里问。
我们有一个文件,它使用自动前置添加到我们服务器上的每个 PHP 文件,其中包含一个名为 Bootstrap 的类,我们用于自动加载、环境检测等。一切正常。
但是,当对同一服务器上的另一个文件的请求之前(即不到一秒甚至同时)出现“内存不足”错误时,会发生以下三种情况之一:
我们用于检查
if(class_exists('Bootstrap')的代码(我们在第一次遇到此错误时用于包装类定义)返回true,这意味着尽管这是自动前置文件,但该类已被声明。我们从自动前置文件中收到“无法重新声明类 Bootstrap”错误,这意味着
class_exists('Bootstrap')返回了false,但它仍然被声明了。- 该文件根本没有前置,导致依赖它的文件出现一次性致命错误。
当然,我们可以尝试修复内存不足问题,因为这些问题似乎会导致其他错误,但由于各种原因,它们在我们的设置中无法修复或很难修复。但这不是重点——在我看来,这是 PHP 中的一个错误,存在某种内存泄漏,导致 auto-prepend 指令出现问题。
这比什么都更令人好奇,因为这种情况很少发生(在我们的高流量服务器上可能每周一次)。但我想知道 - 为什么会发生这种情况,我们可以做些什么来解决它?
我们正在运行 FreeBSD 9.2 和 PHP 5.4.19。
编辑:过去几个月我们在尝试解决此问题时注意到的一些事情:
这似乎只发生在我们的安全服务器上。内存不足问题主要出现在我们的安全服务器上(它们通常来自我们自己的员工试图下载过多数据),所以这可能只是巧合,但值得指出
-
当我们遇到此问题时,
李>get_declared_classes的转储包含触发错误的页面上未使用的类。例如,$_SERVER的输出表明此人在 xyz.com 上,但声明的类之一仅在 abc.com 中使用,这通常是内存不足问题的根源。 所有这一切让我相信 PHP 在出现内存不足错误后没有进行正确的循环结束垃圾收集,这导致
Bootstrap类完全或部分在内存中如果错误发生后足够快,则请求下一页。我对 PHP 垃圾收集还不够熟悉,无法对此采取实际行动,但我认为这很可能是问题所在。
【问题讨论】:
-
可能是。听起来像是一个很难追捕的边缘案例。我会使用dtrace 来记录(a)你的 prepend 的编译,(b)GC 正在做什么,以及(c)错误情况。对于 GC 位,您可能需要编写自己的 static probe。另外,如果你有 APC 正在运行,我会为这些诊断禁用它。
-
谢谢。现在是说服自己这是一个足够大的问题来深入研究解释器和 gc 以修复的困难部分。 :-D
-
您是否在这些服务器上使用任何类型的操作码缓存?您是使用 php 作为模块还是(快速)cgi?您的 server 内存不足,还是 php 脚本刚刚达到极限?
-
无缓存。计算机图形图像。据我所知,它只是达到了
memory_limitini 设置。 -
直截了当 mod_cgi?如果是这样,切换到带有进程隔离的fastcgi,看看是否仍然得到它。
标签: php garbage-collection out-of-memory freebsd