PHP中内存大小超限(尝试分配43148176字节),已耗尽33554432字节的允许内存大小。

355

这个错误信息提示已经出现了,有什么建议吗?

在php中尝试分配43148176字节的内存时,已用尽33554432字节的允许内存大小。


7
请在您的php.ini文件中将最大内存限制增加到64MB。但我可以问一下,为什么您要分配那么多内存?它在哪行代码上失败了? - user19302
1
脚本失败时在做什么?你能发布代码吗? - Neil Aitken
2
PHP在内存使用方面可能非常低效,我经常看到简单的数据网格会因为几百条记录而膨胀到80MB以上。这似乎特别发生在采用面向对象编程方法时。 - TravisO
3
看起来是一个非常巨大的文本文件。 - macbirdie
10
传统上,您会按行读取潜在较大或任意大小的文件,每次读取一行时,会用前一行的内存覆盖。或者您可能只想要查看文件的最新条目。增加内存分配并不是解决方法。 - ekerner
显示剩余3条评论
24个回答

398
如果您的脚本需要分配如此大量的内存,那么您可以通过在php文件中添加以下行来增加内存限制。
ini_set('memory_limit', '44M');

其中44M是你预计要消耗的内存量。

然而,大多数情况下这个错误消息意味着脚本正在做一些不对的事情,增加内存限制只会导致相同的错误消息出现不同的数字。

因此,与其增加内存限制,你必须重写代码,使其不会分配那么多的内存。例如,将大量的数据分成小块来处理,取消不再需要的保存大型值的变量等。


139
你仍然应该查明为什么内存被耗尽。也许你不需要读取整个文件,可以顺序读取。 - macbirdie
8
根据内存的数量和脚本的使用方式,允许以这种方式更改内存使用可能会带来危险。在您的情况下,Don,您可以将数据源分成较小的块并解析所需的内容。很高兴它能够工作,但要小心。 - anonymous coward
6
这个建议对我很有帮助。通过函数ini_set()可以在脚本中动态地增加内存限制:ini_set('memory_limit', '128M'); - mente
49
各位,请不要选择这种快速解决方案。它在长期中可能会对你造成伤害。作为一名优秀的程序员,你应该找出内存消耗增加的原因,并根据需要进行增加,而不是将其保持为“无限制”。 - Sumoanand
130
哇,这个得到大量顶赞的答案对我来说似乎是非常糟糕的做法。-1! - Ambidex
显示剩余25条评论

71

以下是两种简单的方法来增加共享主机上的限制:

  1. 如果您可以访问PHP.ini文件,请更改PHP.ini中的这一行,如果您的这一行显示32M,请尝试将其改为64M: memory_limit = 64M;脚本可使用的最大内存量(64MB)

  2. 如果您无法访问PHP.ini,请尝试将以下内容添加到.htaccess文件中: php_value memory_limit 64M


53

您的脚本使用了过多的内存。如果您在PHP中有一个无限循环并且每次循环都创建对象或向数组添加元素,那么这种情况经常会发生。

检查是否存在无限循环。

如果不是这个问题,请通过将已完成的对象设置为null来帮助PHP销毁它们。例如:$OldVar = null;

同时,检查代码中实际发生错误的位置。您是否期望该行分配大量内存?如果不是,请尝试弄清楚出了什么问题...


3
我曾经遇到过这个问题,后来发现我不小心创建了一个递归函数,导致代码执行期间的任意时刻都会耗尽内存。这个问题的好处是,在寻找内存泄漏时,我现在拥有世界上最高效的内存代码。 - Kris Selbekk
1
为了其他人不要跟着兔子进洞,我认为Symfony中的Doctrine与Monolog存在问题。当出现PDO异常时,它会创建无限循环的异常,因为它会尝试对异常进行异常处理,从而隐藏真正的问题(在我的情况下是一个损坏的数据库文件)。 - Desislav Kamenov

49

正在进行:

ini_set('memory_limit', '-1');

这并不是好的做法。如果你想要读取一个非常大的文件,最好的办法是逐位复制它。尝试以下最佳实践的代码。

$path = 'path_to_file_.txt';

$file = fopen($path, 'r');
$len = 1024; // 1MB is reasonable for me. You can choose anything though, but do not make it too big
$output = fread( $file, $len );

while (!feof($file)) {
    $output .= fread( $file, $len );
}

fclose($file);

echo 'Output is: ' . $output;

7
难以置信所有这些人都建议将memory_limit设置为-1...在生产服务器上做这种事情太疯狂了。感谢提供一个更干净的解决方案。 - JohnWolf
3
在最佳实践中,关闭文件处理程序是一个好习惯,可以放在 while 循环后面:fclose($file) - kodeart
5
如果文件大小为100MiB,而PHP内存限制仍然设置为32 MiB,那么这有什么帮助呢?你可以按1MiB的安全块来读取它,但一旦循环到第31次迭代时,它就会被连接到一个变量中,该变量将使用所有可用的内存。这有什么改善吗?只有类似输出这些块的方法,才不需要将它们全部存储在一个变量中,这样才能解决问题。 - helvete

25

我在使用laravel 5.6和php7.2时遇到了同样的问题。我只需将php.ini中的memory_limit = 128M变量增加到符合我的应用程序要求的256M、512M或1048M等大小即可。现在它正常运行。


这可以作为短期解决方案,但除非您预计这种内存使用情况,否则很可能表明出现了问题。 - qozle

21

很遗憾,使用PHP编程时更容易消耗内存,而且比你意识到的要快。复制字符串、数组和对象而不使用引用会导致这种情况,尽管PHP 5比PHP 4更自动化处理此问题。但是将您的数据集完整地处理几个步骤也比一次处理最小逻辑单元浪费更多。经典例子是处理来自数据库的大型结果集:大多数程序员将整个结果集获取到数组中,然后使用foreach()一次或多次遍历它。使用while()循环一次获取并处理一行更具有内存效率。相同的情况也适用于处理文件。


这似乎很有可能就是它的原因。 - Kzqai

15

如果你想读取大文件,应该逐位读取而不是一次性读取。


这是简单的数学问题:如果你一次性读取一个1MB的大文件,那么至少需要1MB的内存同时存储数据。

所以你应该使用fopenfread逐位读取它们。


1
通过以下方式解决:$fh = fopen($folder.'/'.$filename, "rb") or die(); $buffer = 1024*1024; while (!feof($fh)) { print(fread($fh, $buffer)); flush(); } fclose($fh); - Avatar

8
你可以在脚本中的所有代码之前执行以下行来增加允许php脚本使用的内存:
ini_set('memory_limit','-1'); // enabled the full memory available.

同时,在脚本中也要释放不需要的变量。

这不是一个好的解决方案。我认为这意味着你让脚本肆意运行并使用尽可能多的内存。关于使用过多内存的错误很可能是某些问题的迹象,因此这种方法消除了症状,但也让问题变得更严重(字面上)。 - qozle

8
我也遇到了同样的问题,找不到phpinfo.ini、php.ini或.htaccess文件。最终,我查看了一些php文件,打开并检查了其中的代码,以查找内存。最终,这个解决方案就是我想出来的,并且对我很有效。我正在使用wordpress,所以这个解决方案可能只适用于wordpress内存大小限制问题。我的解决方案是,打开/public_html/wp-includes文件夹中的default-constants.php文件。使用代码编辑器打开该文件,并在wp_initial_constants范围下查找内存设置,或者Ctrl+F查找单词“memory”。在那里,您将看到WP_MEMORY_LIMITWP_MAX_MEMORY_LIMIT。只需增加内存限制即可,我的情况下是64 MB,我将其增加到128 MB,然后到200 MB。
// Define memory limits.
if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
    if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
        define( 'WP_MEMORY_LIMIT', $current_limit );
    } elseif ( is_multisite() ) {
        define( 'WP_MEMORY_LIMIT', '200M' );
    } else {
        define( 'WP_MEMORY_LIMIT', '128M' );
    }
}

if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
    if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
        define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
    } elseif ( -1 === $current_limit_int || $current_limit_int > 268435456 /* = 256M */ ) {
        define( 'WP_MAX_MEMORY_LIMIT', $current_limit );
    } else {
        define( 'WP_MAX_MEMORY_LIMIT', '256M' );
    }
}

顺便说一句,请不要编写以下代码,因为那是不好的做法:
ini_set('memory_limit', '-1');

1
适用于WordPress网站,其中无法访问.htaccess和php.ini文件。+1 - Mustafa sabir
我认为在“核心”WordPress文件上更改这些限制并不是一个好主意;相反,你可以很容易地在wp-config.php上添加这些限制,这样它们就不会被未来的WordPress更新覆盖。 此外,一些安全插件(例如WordFence)会抱怨如果更改了“核心”WordPress文件... - Gwyneth Llewelyn
1
@GwynethLlewelyn 我不知道如何做到这一点,你能详细说明一下吗? - garakchy
1
哦...只需编辑wp-config.php并添加这两行代码(即define( 'WP_MEMORY_LIMIT', '200M' );define( 'WP_MAX_MEMORY_LIMIT', '256M' );)。与“核心”WP下的文件(即wp-includes下的所有文件)不同,这些文件将被WP升级覆盖,而wp-config.php不会——它正是为了覆盖WP常量而存在的! - Gwyneth Llewelyn
1
“不良实践”是情境相关的。对于短时间运行的进程,使用“-1”是可以接受的。例如,用于运行单元测试或composer安装等操作的php构建容器。但是,请勿将其设置为生产站点的运行方式。 - emmdee
如果匆忙的话,可以使用 ini_set('memory_limit', '-1'); 如果这是一次性操作,比如种子填充器,则应将其返回到先前的值。 - Maksim Dimitrov

7
我注意到很多答案只是试图增加脚本的内存量,这是有其作用的,但更多时候是因为某些东西过于慷慨地使用了内存,由于数量或大小未预见到。显然,如果你不是脚本的作者,除非你感到雄心勃勃,否则你就处于作者的掌控之下 :) PHP文档甚至说内存问题是由“编写不良的脚本”引起的。
应该提到的是,ini_set('memory_limit', '-1');(无限制)可能会导致服务器不稳定,因为0字节空闲=糟糕的事情。相反,通过脚本所要做的事情和机器上可用内存的数量找到一个合理的平衡。

更好的方法:如果您是脚本的作者(或有雄心壮志),可以使用xdebug调试此类内存问题。最新版本(2.6.0-发布于2018-01-29)重新引入了内存分析,显示消耗大量内存的函数调用。它会暴露脚本中难以找到的问题。通常,低效率出现在一个循环中,该循环无法处理其接收到的数据量,但每种情况都需要读者自行解决 :)

xdebug文档很有帮助,但归结为3个步骤:

  1. 安装 - 可以通过apt-getyum等方式获取
  2. 配置 - xdebug.ini: xdebug.profiler_enable = 1, xdebug.profiler_output_dir = /where/ever/
  3. 使用QCacheGrindKCacheGrind等工具查看分析结果

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