如何防止 PHP 输出缓冲区超过内存限制?

3

我的PHP应用程序大多都在开头有一个ob_start,然后运行所有代码,最后在一切完成之后输出内容,有时会进行一些修改。

ob_start()
//Business Logic, etc
header->output();
echo apply_post_filter(ob_get_clean());
footer->output();

这将确保在网站内容部分显示PHP错误,并且错误不会干扰header和session_*调用。
我的唯一问题是,对于一些大型页面,PHP会耗尽内存。我该如何防止这种情况发生?
一些想法:
1. 将所有缓冲的内容写入临时文件并输出。 2. 当缓冲区达到一定大小时输出它。虽然这可能会干扰后置过滤器。 3. 提高内存限制(感谢 @troelskn)。
每种方法的缺点是什么?特别是提高内存限制?
5个回答

6

你不能提高内存限制吗?这对我来说似乎是最好的解决方案。

编辑:显然,仅仅因为一个脚本达到了限制而提高内存限制会引起一些警惕,但在我看来,这似乎是一个合法的情况 - 例如,该脚本实际上产生了相当大的输出块。因此,您必须将输出存储在某个地方,而内存似乎是性能和便利性方面的最佳选择。

我还应该指出,内存限制设置只是一个限制。不消耗多少内存的脚本,如果你提高了限制,它们也不会消耗更多。其存在的主要原因是防止行为不端/有缺陷的脚本导致整个服务器崩溃。如果您在共享主机上有很多业余爱好者进行黑客攻击(PHP已经被广泛用于此),那么这一点非常重要。因此,如果这是您自己的服务器,或者至少您通常知道自己在做什么,那么拥有较低的内存限制并没有真正的好处。


我尝试过了,但是我的内心总有些不舒服,觉得提高内存限制可能会有什么缺点吗? - Jrgns

2
我建议您尝试分阶段加载文件,或将其拆分为较小的部分以便包含。具体如何操作取决于文件本身,但这样可以让您以2MB大小的块加载它,如果没有生成任何错误,则使用ob_flush()在加载下一个块之前发送它。
例如,您提到它是PHP模板;如果您说的是混合了PHP/HTML的文件,在执行时会产生输出,则可以尝试在模板中添加某种形式的块标记来分隔模板的不同部分。这样,您只需要读取当前块的末尾,然后输出它并继续。如果您有循环等内容,这会变得更加困难,但通常总有方法来解决它。例如,通过在您的模板中添加触发主脚本中的方法/函数的PHP来处理循环输出。
您还可以考虑在加载模板之前预验证模板的机制,以便您无需担心错误会潜藏在页面中。
虽然更改内存限制在短期内可以“解决”问题,但如果可能的话,应避免使用这种内存使用方式。一般来说,如果可以避免将任何大型内容加载到内存中,请尽量避免这样做,或者在最早的机会将其输出,因为这意味着数据已经在传输到用户,这可以减少页面的首字节时间。

2
您应该首先提高内存限制,特别是如果您的唯一其他解决方案是通过临时文件进行操作。使用临时文件有各种缺点(主要是速度较慢),如果您确实需要在输出之前存储缓冲区,则可以寻找memcachedAPC cache。这将使您能够执行与文件大致相同的操作,但具有RAM的快速访问。
尽管如此,我必须说这总体上是一个糟糕的想法。如果缓冲区当前无法正常工作,则很可能存在一些不同的构建方式,以使您的站点更好地运行。

2
如果php错误是缓冲输出的唯一原因,请考虑使用set_error_handler。使用此函数,您可以为脚本中的错误定义自定义回调。使用它将消息保存在某个地方并稍后打印出来。 http://www.php.net/set_error_handler

不仅仅是为了错误。请注意 apply_post_filter 函数会改变输出结果。 - Jrgns

1

如果你因为输出而耗尽内存,那么你必须有大量的数据输出或者非常低的内存限制。大约四年前,8mb 的内存限制已经足够普遍和合理了。但是随着使用对象和更好的编码风格,我所遇到的脚本的内存使用量增加了。

嗯...你的脚本在哪里耗尽了内存呢?如果总是在输出过滤函数中,也许它们只需要优化下?memory_get_usage() 将返回该点脚本正在使用的内存量。

你现在运行的内存限制是多少?你在共享环境中运行吗? 目前,我的服务器内存限制在 64 到 128 之间。

如果你只想增加特定子集的脚本限制,那么你可以单独针对每个脚本进行设置:

ini_set('memory_limit','64M');

如果您希望脚本没有限制,可以将其设置为-1


该服务器是几个非常大的Web应用程序的生产服务器。我认为内存限制为128Mg。当我将一个非常大的PHP模板文件加载到缓冲区时,我会遇到限制。 - Jrgns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接