增加PHP memory_limit。在什么时候会变得不理智?

42
在我目前处理的系统中,有一个进程需要将大量数据加载到数组中进行排序/聚合等操作。我知道这个进程需要优化内存使用,但在短期内它只需要能够正常工作。
由于加载到数组中的数据量很大,我们一直在达到内存限制。已经增加过多次了,我想知道增加到某个点是否总体上变得不可取?还是< strong>只有机器拥有的RAM大小的问题?
该机器拥有2GB的RAM,memory_limit目前设置为1.5GB。我们可以轻松地向机器添加更多RAM(并且无论如何都会这样做)。
其他人是否遇到过这种问题?解决方案是什么?

6
你不必担心设置内存限制,而应该找出内存泄漏的原因并解决它。仅仅增加内存限制并不是解决方案,这只是规避了代码中存在的问题。查看你正在设置和取消哪些对象的值以清除泄漏。 - Petrogad
你能具体说明数据量吗?你所说的“大”是指多大? - Jamison Dance
8
楼下的Frederico说错了,OP不是要修复内存泄漏,他正在寻求PHP处理大型数据集的解决方案。 - arul
@Frederico 我知道这不是一个理想的答案,但我正在寻求建议,直到我们有机会做得更好。@Jergason 这是来自数据库查询的表格数据,大约500k行,15列。大是相对于可用内存而言的,但已经足以达到当前1.5GB的内存限制。不确定最终大小,因此问题是“什么时候太多了?” - Brenton Alker
你能告诉我们脚本执行的任务信息吗?也许我们可以帮助你优化算法,消除过度的内存消耗。 - Vladislav Rastrusny
3个回答

60
PHP运行为Apache模块以提供网页的memory_limit配置应考虑您可以在机器上同时拥有多少个Apache进程--请参见Apache的MaxClients配置选项。如果MaxClients是100并且您有2,000 MB的RAM,则非常快速的计算将显示您不应使用超过20 MB(因为20 MB * 100个客户端= 2 GB或RAM,即服务器总内存量)的memory_limit值。这还没有考虑到可能在同一台服务器上运行其他东西,如MySQL,系统本身等,而且Apache可能已经在使用一些内存。
当然,这也是一个“最坏情况”,考虑到每个PHP页面都在使用它可以使用的最大内存量。
如果您只需要一个作业使用如此大量的内存,我不会增加运行为Apache模块的PHP的memory_limit
相反,我会从命令行(或通过cron作业)启动该作业,并在这种唯一的情况下指定更高的memory_limit
这可以使用php的-d选项完成,例如:
$ php -d memory_limit=1GB temp.php
string(3) "1GB"

考虑到这种情况,temp.php仅包含:

var_dump(ini_get('memory_limit'));

在我看来,这比增加Apache PHP模块的memory_limit更安全--当我有一个大数据集或一些我无法优化或分页的重型内容时,通常会这样做。


如果您需要为PHP CLI执行定义多个值,也可以使用-c选项告诉它使用另一个配置文件,而不是默认的php.ini文件:

php -c /etc/phpcli.ini temp.php

这种方式,你有:

  • /etc/php.ini 用于 Apache,内存限制 (memory_limit) 低,最长执行时间 (max_execution_time) 短...
  • /etc/phpcli.ini 用于从命令行运行的批处理程序,几乎没有限制

这确保你的批处理程序能够运行 - 你的网站仍然有安全保障 (memory_limitmax_execution_time 是安全措施)


然而,如果你有时间优化你的脚本,你应该这样做;例如,在需要处理大量数据的情况下,分页是必须的 ;-)


是的,限制只会提高需要它的进程。不幸的是,在这种情况下分页无法帮助;最终结果只有少数(大约20个)统计数字,只是处理需要空间。 - Brenton Alker
哦,好的...那么,我想这在启动该进程时取决于你有多少“空闲”内存:如果你在深夜启动它,当几乎没有人使用你的服务器时,也许1.5 GB就可以了(我会使用更多的内存,留一些给系统的其他部分)-但只有你能说出那个时间你的服务器有多少负载。 - Pascal MARTIN
4
在某些PHP版本(例如带Suhosin-Patch的PHP 5.3.15)中,设置值为1G而非1GB。请进行测试,否则PHP会将限制设置为最低值,导致您的脚本无法执行。例如使用 php -d memory_limit=1G -r "echo ini_get('memory_limit');" 进行设置。 - E Ciotti
我在Ubuntu 14.04上的Apache2配置中找不到MaxClients选项。如果没有这个选项,Apache默认会做什么? - BadHorsie

2
你尝试将数据集分成较小的部分,一次只处理一个部分吗?
如果您从磁盘文件中获取数据,则可以使用fread()函数加载较小的块,或者在数据库情况下使用某种未缓冲的db查询。
我自v3.something以来就没有检查过PHP,但您也可以使用一种云计算形式。 1GB的数据集似乎足够大,可以在多台机器上处理。

计划是仅在需要时读取数据(就像您使用fread()建议的那样),但这是我们尚未进行的重构。 - Brenton Alker
这是我个人认为正确的答案:除非数据集完全相关,否则通常可以一次处理一部分,很少需要将所有数据都保存在内存中。正如楼主指出的那样,这通常需要进行较大的重构。 - Piskvor left the building

1

假设您知道脚本存在内存问题需要修复,且只寻找短期解决方案,那么我不会讨论如何进行分析和解决内存问题的方法。听起来您会处理这个问题。

因此,我认为您需要牢记的主要事项是:

  • 系统的总内存负载
  • 操作系统的能力

PHP仅是系统的一个小组成部分。如果您允许它占用大量RAM,那么其他进程将受到影响,这可能反过来影响脚本本身。特别是,如果您从数据库中提取了大量数据,则您的DBMS可能需要大量内存才能为查询创建结果集。作为快速解决方案,您可能希望尽快识别运行的任何查询并释放结果,以便在长时间运行作业时获得更多内存。

关于操作系统的能力,您应该记住,您可能正在运行的32位系统在没有特殊处理的情况下只能寻址高达4GB的RAM。通常情况下,限制可能会更小,具体取决于如何使用它。一些Windows芯片组和配置实际上可以使系统可用内存少于3GB,即使物理安装了4GB或更多。您应该检查一下您的系统可以寻址多少内存。
您说您已经多次增加了内存限制,所以显然这个任务的范围越来越大。如果您已经使用了1.5GB,那么即使再安装2GB内存,也只是短暂的缓解。

其他人遇到过这种问题吗?有什么解决方案吗?

我认为您可能已经知道唯一真正的解决方案是尽快优化脚本,否则您最终将得到一个无法运行的任务。

这台机器几乎专门用于PHP,数据库服务器是分开的。之前的限制增加并不是因为工作量增加了(虽然会增加,但不会那么快),而是因为它们不足以“修复”问题(所以我们尝试了更大的限制)。现在我们有了一个让进程运行的限制,但这绝对只是一个短期解决方案。关于系统限制的好处,它是一台64位的机器,我们将无论如何增加RAM。无论如何,我认为你已经消除了我的担忧,即向单个进程投入如此多的内存是荒谬的。RDBMS可以做到,我为什么不能呢 :) - Brenton Alker

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