增加 PHP memory_limit。啥时候会变得疯狂?
Posted
技术标签:
【中文标题】增加 PHP memory_limit。啥时候会变得疯狂?【英文标题】:Increasing PHP memory_limit. At what point does it become insane?增加 PHP memory_limit。什么时候会变得疯狂? 【发布时间】:2010-11-28 08:23:32 【问题描述】:在我目前正在开发的系统中,有一个进程将大量数据加载到数组中以进行排序/聚合/任何操作。我知道这个过程需要优化内存使用,但在短期内它只需要工作。
鉴于加载到数组中的数据量,我们不断达到内存限制。它已经增加了好几次,我想知道增加它是否会变成一个坏主意?还是只是机器有多少 RAM 的问题?
机器有 2GB 的 RAM,memory_limit 当前设置为 1.5GB。我们可以轻松地为机器添加更多 RAM(无论如何都会)。
其他人遇到过这种问题吗?以及解决方案是什么?
【问题讨论】:
老实说,您不应该关心设置内存限制,而是要找出内存泄漏的位置并修复它。仅仅增加 memory_limit 不是解决方案,它是在避免代码中的问题。查看您正在设置和取消设置值的对象以清除泄漏。 你能具体说明一下数据量吗?大是什么意思? @Frederico:OP 并没有试图修复内存泄漏,他正在寻求一种在 php 中处理非常大的数据集的解决方案。 @Frederico 我知道这不是一个理想的答案,但我正在寻求建议,直到我们有机会做得更好。 @Jergason 这是来自数据库查询的表格数据,约 50 万行,15 列。大是相对于可用内存而言的,但足以达到当前 1.5GB 的内存限制。不确定最终的大小,因此问题是“什么时候太多了?” 你能给我们关于脚本执行的任务的信息吗?也许我们会帮助您优化算法以消除过多的内存消耗。 【参考方案1】:memory_limit
的 PHP 作为 Apache 模块运行到服务器网页的配置必须考虑到您可以在机器上同时拥有多少个 Apache 进程 - 请参阅 Apache 的 MaxClients
配置选项.
如果MaxClients
是 100 并且您有 2,000 MB 的 RAM,一个非常快速的计算将表明您不应该使用超过 20 MB *(因为 20 MB * 100 个客户端 = 2 GB 或 RAM,即总量您的服务器拥有的内存)* memory_limit 值。
这还没有考虑到可能还有其他东西在同一台服务器上运行,比如 mysql、系统本身……而且 Apache 可能已经为自己使用了一些内存。
当然,这也是一个“最坏的情况”,它认为每个 PHP 页面都在使用它可以使用的最大内存量。
在你的情况下,如果你只需要这么大的内存来完成一项工作,我不会为作为 Apache 模块运行的 PḦP 增加 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_limit
和 max_execution_time
是安全措施)
不过,如果你有时间优化你的脚本,你应该;例如,在那种你必须处理大量数据的情况下,分页是必不可少的;-)
【讨论】:
是的,只有需要它的进程才会提高限制。不幸的是,在这种情况下,分页无济于事。最终结果只是少数(20 个左右)统计数字,只是需要空间的处理。 哦,好吧...然后,我想这取决于您在启动该进程时有多少“空闲”内存:如果您在半夜启动它,几乎没有没有人使用您的服务器,也许 1.5 GB 可能还可以(我会使用更多,以便为系统的其余部分留出一些内存)——但只有您可以说当时您的服务器加载了多少。 在某些 PHP 版本(例如带有 Suhosin-Patch 的 PHP 5.3.15)中,设置为 1G,而不是 1GB。测试它,否则 PHP 会将限制设置为最低值,您的脚本将无法执行,例如使用php -d memory_limit=1G -r "echo ini_get('memory_limit');"
我在 Ubuntu 14.04 上的 Apache2 配置中找不到 MaxClients
。如果没有这个选项,Apache 默认会做什么?【参考方案2】:
您是否尝试过将数据集拆分为更小的部分并一次只处理一个部分?
如果您从磁盘文件中获取数据,您可以使用fread()
函数来加载较小的块,或者在数据库的情况下使用一些sort of unbuffered db query。
自 v3.something 以来我没有检查过 PHP,但您也可以使用某种形式的云计算。 1GB 数据集似乎足够大,可以在多台机器上处理。
【讨论】:
计划是仅根据需要读取数据(正如您使用 fread() 建议的那样),但这是我们尚未进行的重构。 这是实际的正确答案,IMNSHO:除非数据集完全相关,否则通常可以一次处理一个部分,很少需要将所有部分保存在内存中。正如 OP 所指出的,这通常需要进行重要的重构。【参考方案3】:鉴于您知道您的脚本存在内存问题需要修复,并且您只是在寻找短期解决方案,那么我不会解决go about profiling 和解决您的内存问题的方法。听起来你会做到的。
所以,我想说你必须记住的主要事情是:
系统上的总内存负载 操作系统功能PHP 只是系统的一小部分。如果你让它吃掉你的大量内存,那么其他进程就会受到影响,这反过来又会影响脚本本身。值得注意的是,如果您要从数据库中提取大量数据,那么您的 DBMS 可能需要大量内存才能为您的查询创建结果集。作为一种快速解决方法,您可能希望识别正在运行的任何查询并尽快释放结果,以便为长时间的作业运行提供更多内存。
就操作系统功能而言,您应该记住,您可能在其上运行的 32 位系统在没有特殊处理的情况下最多只能寻址 4GB 的 RAM。通常限制可能会小得多,具体取决于它的使用方式。某些 Windows 芯片组和配置实际上可以为系统提供不到 3GB 的可用空间,即使实际安装了 4GB 或更多。您应该检查一下您的系统可以处理多少。
你说你已经增加了几次内存限制,所以显然这项工作的范围越来越大。如果您的内存达到 1.5Gb,那么即使再安装 2Gb 的 RAM 听起来也只是短暂的缓解。
有没有其他人遇到过这种情况 问题?以及解决方案是什么?
我想您可能已经知道,唯一真正的解决方案是尽快分解并花时间优化脚本,否则您最终会得到一个太大而无法运行的工作。
【讨论】:
这台机器非常专用于 PHP,数据库服务器是独立的。之前的限制增加并不是因为工作在增加(虽然会增加,但不会那么快),它们不足以“解决”问题(所以我们尝试了更大的限制)。我们现在有一个允许进程运行的限制,但这绝对只是一个短期解决方案。关于系统限制的好点,它是一台 64 位机器,无论如何我们都会增加 RAM。无论如何,我认为你已经减轻了我的担忧,即在一个进程中投入这么多内存是荒谬的。 RDBMS 做到了,为什么我不能:)以上是关于增加 PHP memory_limit。啥时候会变得疯狂?的主要内容,如果未能解决你的问题,请参考以下文章
Composer 内存不足 - 需要其他方法来增加 PHP memory_limit