内存不足错误后,PHP会自动添加错误

时间:2013-12-18 21:30:35

标签: php garbage-collection out-of-memory freebsd

这可能更适合服务器故障,但我想我先问这里。

我们的服务器上的每个PHP文件都有一个文件,它使用自动前置,其中包含一个名为Bootstrap的类,我们用它来进行自动加载,环境检测等。这一切都正常。

但是,当在同一服务器上的另一个文件的请求之前(即,小于一秒或甚至同时)存在“OUT OF MEMORY”错误时,会发生以下三种情况之一:

  1. 我们用于检查if(class_exists('Bootstrap')的代码(我们在第一次收到此错误时用于包装类定义)返回true,这意味着该类已经被声明,尽管这是自动 - 文件。

  2. 我们在自动预装文件中收到“无法重新声明类Bootstrap”错误,这意味着class_exists('Bootstrap')返回false但仍以某种方式声明了它。

  3. 该文件根本没有前置,导致依赖它的文件出现一次性致命错误。
  4. 当然,我们可以尝试修复内存不足问题,因为这些问题似乎导致了其他错误,但由于各种原因,它们在我们的设置中无法修复或者很难修复。但这不是重点 - 在我看来,这是PHP中的一个错误,存在某种内存泄漏导致auto-prepend指令出现问题。

    这比任何事情都更好奇,因为这很少发生(可能每周一次在我们的高流量服务器上)。但我想知道 - 为什么会发生这种情况,我们可以做些什么来解决它?

    我们正在使用FreeBSD 9.2运行PHP 5.4.19

    编辑:过去几个月我们在尝试解决这个问题时注意到的一些事情:

    • 似乎只发生在我们的安全服务器上。内存不足问题主要出现在我们的安全服务器上(他们通常来自我们自己的员工,试图下载太多数据),所以这可能只是巧合,但值得指出

    • 遇到此问题时,get_declared_classes的转储包含未在触发错误的页面上使用的类。例如,$_SERVER的输出表示此人在xyz.com上,但其中一个声明的类仅用于abc.com,这是内存不足问题通常源自的地方。

    • 所有这些让我相信PHP在获得内存不足错误后没有进行正确的循环结束垃圾收集,导致Bootstrap类完全或部分地处于如果错误发生后很快就会在下一页请求内存。我对PHP垃圾收集的熟悉程度不足以实际采取行动,但我认为这很可能是问题所在。

3 个答案:

答案 0 :(得分:0)

即使class_exists返回false,如果存在同名的接口,它也永远不会返回true。但是,您不能声明具有相同名称的接口和类。

尝试运行class_exists('Bootstrap') && interface_exists('Bootstrap')以确保不重新声明。

答案 1 :(得分:0)

您看过__autoload函数吗?

我相信您可以通过在代码中创建类似的功能来解决此问题:

function __autoload($className)
{
    if (\file_exists($className . '.php')) 
        include_once($className . '.php');
    else 
        eval('class ' . $className . ' { function __call($method, $args) { return false; } }');
}

如果您有一个名为Bootstrap.php的文件,并且其中声明了Bootstrap类,则PHP将自动加载文件,否则声明一个可以处理其中任何函数调用的ghost类,从而避免出现任何错误消息。请注意,对于幻影功能,我使用了__call魔术方法。

答案 2 :(得分:0)

如果不解决内存不足问题,可能无法“解决”问题。在不知道您使用的框架的情况下,我将仅列出需要考虑的领域。

您说“他们通常来自我们自己的员工,试图下载过多的数据”。我将从这里开始,因为这可能是最大/最大的优化机会,所以我想到了一些想法。

  • 如果正在下载的数据是文件,也许您可​​以使用流将读取的数据块化为恒定大小,这样在大下载量时不会占用内存。

  • 您可以下载队列,限制吗?

  • 如果数据来自数据库,则除了优化查询之外,您还可以对查询进行速率限制,减小结果集大小,并理想地将此类工作负载转移到具有镜像数据的专用环境中。

  • 确保您的代码以负责任的方式释放文件指针和数据库连接,将其留给PHP拆除,这可能会在高流量情况下导致垃圾回收延迟和某种级联效果。

关于记忆力限制的其他低落果实

  • 您正在运行php 5.4.19,如果您的软件允许,请考虑更新到更新版本“ PHP 5.4自2015年以来未进行修补”,而PHP 7则带来了很多性能改进。

  • >
  • 如果您有客户端应用程序在监视它的xhr和整个网络活动,请查找过多的轮询和挂起连接。

  • 对于自动加载器,基于您的注释“我们遇到此问题时,get_declared_classes的转储包含触发错误的页面上未使用的类”,您可能需要检查实现,以使确保它没有加载某种捆绑的类缓存,如果您使用的是作曲家,则dump-autoload可能会有所帮助。

  • 会话,我已经看到一些应用程序基于cookie和会话加载文件,如果您有这样的设置,我会审核该逻辑并确保没有粘性会话加载不需要的资源。

从您的问题很明显,您正在运行多租户服务器。没有适当的统计数据,很难具体说明,但我认为这显然不是PHP问题,因为根据您的描述,它似乎有些孤立。

正确的调试和分析

我建议安装一个PHP探查器,即使是很短的时间,新的文物也不错。您将能够准确了解正在发生的事情,并拥有解决正确问题的数据。我认为他们有免费试用版,应该可以使您指明正确的方向……也有其他人,但是他们的名字此刻不在我眼前。