致命错误:允许的134217728字节的内存大小已用尽(CodeIgniter + XML-RPC)


617

我有一堆客户端销售点(POS)系统,这些系统定期将新的销售数据发送到一个集中式数据库,该数据库将数据存储到一个大型数据库中以生成报告。

客户端POS基于PHPPOS,我已经实现了一个模块,该模块使用标准XML-RPC库将销售数据发送到服务。该服务器系统基于CodeIgniter构建,并为Web服务组件使用XML-RPC和XML-RPCS库。每当我发送大量销售数据时(从sales表中少到50行,而来自sales_items中与销售中每个项目有关的单独行)都会出现以下错误:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)

中的默认值为128M php.ini,但我认为这是一个很大的数字。实际上,我什至尝试将此值设置为1024M,而这样做所花费的时间更长。

至于我采取的步骤,我尝试禁用服务器端的所有处理,并操纵它以返回固定响应,而不管输入如何。但是,我认为问题在于实际发送数据。我什至尝试禁用PHP的最大脚本执行时间,但仍然出错。


5
我有点困惑...错误发生在哪里-在客户端还是服务器中?在哪个阶段...客户端发送,服务器接收,服务器处理,服务器发送,客户端接收或客户端处理?
格雷格,

2
该错误似乎在客户端发送或服务器接收期间发生。我尝试禁用所有服务器端处理,并绑定它以发送固定响应,而不管发送的数据如何。如果我发送了一定数量的数据,则会发生错误。我正在更改PHP.ini设置。
09年

42
内存限制为128MB,ini_set('memory_limit', '256M');

9
Summary否决了所有“只是忽略泄漏”的答案,将CodeIgniter与Drupal混淆的人,以及仅复制并粘贴其他人的答案以获取积分的人。在这一答案的质量很糟糕。
Matti Virkkunen 2013年

Answers:


697

改变memory_limitini_set('memory_limit', '-1');不是一个妥善的解决办法。请不要那样做。

您的PHP代码可能在某处存在内存泄漏,并且您告诉服务器只使用它想要的所有内存。您根本不会解决问题。如果监视服务器,您会发现它现在可能已用完大部分RAM,甚至交换到磁盘。

您可能应该尝试在代码中查找有问题的代码并进行修复。


173
@Jeff,您大概有95%的时间是正确的。但是,有时您确实确实需要更多的内存。例如,假设您的应用正在将大量数据加载到内存中进行处理(例如,包含15k组件的物料清单)。代码并非总是错误的,有时您只需要更多的内存(例如256M而不是128M)。但是我同意将其设置为-1是非常糟糕的。但是在运行时为合理的情况调整内存限制是完全可以接受的。
Pyrite

24
@pyrite是的,有时进程需要更多的内存是正确的,但是您应该将内存限制增加到一些合理的数量,如您所说的256MB或512MB,为什么不但不-1;)
Lukas Lukac 2014年

9
@jeff我完全同意,值-1可能是有用的只有在开发环境中测试目的。
Esolitos 2015年

4
在您为其余5%命名的情况下,@ Pyrite会分块读取数据并使用工作程序来处理它,而不是使用更多的内存。该解决方案也可以扩展,但是您的建议将无法正常工作,只是如果数据增长,随着时间的推移,您会在服务器中不断填充越来越多的内存。
burzum

2
以最常见的方式,当您尝试获取所有更多php内存限制的数据时,ORM中的这种麻烦。例如,当您尝试生成每月报告时。
Stepchik

213

ini_set('memory_limit', '-1');覆盖默认的PHP内存限制


16
@williamcarswell; 在这种情况下,-1PHP是一个无限的值。
Alix Axel 2013年

7
@ArseniuszŁozicki-它也会消耗服务器无法节省的资源。
肯·威廉姆斯

124
感到遗憾的是,这样的投票太多了。当人们需要更多内存时,使用php.ini编辑或ini_set将其设置为准确的值是一个非常有效的解决方案。将其设置为无限是危险的黑客行为:(
杰夫·戴维斯

24
@ user1767586然后将其设置为合理的值。您可以通过将脚本设置为1024M来防止脚本引发错误。如果这个答案说了ini_set('memory_limit','1024M'); 您可以将其复制粘贴并确定。通过将其设置为-1,您将自己设置为具有消耗所有内存的脚本。特别是如果您定期执行此操作。在引号中加上“危险”并不会减少危险。您确实可以使用主机服务器。也许开始破坏数据。我不知道,也许丢了工作?听起来对我来说很危险。:|
杰夫·戴维斯

3
痛心地看到,对于+161票和-3票的答案是相同的:(
akarthik10

130

正确的方法是编辑php.ini文件。编辑memory_limit您想要的值。

从您的问题开始,128M(已经超过了默认限制),因此您的代码存在严重问题,因为它占用的时间不多。

如果您知道为什么要花那么多钱,而又想让它设置得memory_limit = 512M更高或更高,那您应该很好。


7
老实说,如果您缓存大量数据,这是正确的答案。对于某些脚本,128M是不够的。512M或1024M通常就足够了,但是您必须视情况决定。
杰夫·戴维斯

2
是的,但是,如果用户数量会更多,则尽量避免占用大量内存
Basav 2014年

2
memory_limit = -1; 在php.ini中设置

2
@YumYumYum删除memory_limit,仅在以其他方式监视内存使用时才需要。如果操作系统以某种方式占用大量内存,它将终止该进程。
Flimm 2015年

因此,如果您正在运行一个使用大量内存的脚本,而您只需要运行一次,则可以在执行时增加该进程的内存限制,然后在一次之后再次降低内存限制吗?脚本运行?
chromechris

95

PHP的内存分配可以永久或临时调整。

永久性

您可以通过两种方式永久更改PHP内存分配。

如果您有权访问php.ini文件,则可以将其值编辑为所需memory_limit的值。

如果您无权访问php.ini文件(并且您的虚拟主机允许访问),则可以通过.htaccess文件覆盖内存分配。添加php_value memory_limit 128M(或任何您想要的分配)。

临时

您可以从PHP文件中即时调整内存分配。您只需拥有代码ini_set('memory_limit', '128M');(或任何所需的分配)。您可以通过将值设置为“ -1”来删除内存限制(尽管机器或实例限制可能仍然适用)。


2
谢谢,我没有想到要检查是否有人在.htaccess中设置了该值,而该值覆盖了php.ini,因此我无法弄清楚为什么+1
HostMyBus

61

在PHP脚本中很容易发生内存泄漏-特别是在使用抽象(例如ORM)的情况下。尝试使用Xdebug来分析脚本,并找出所有内存的去向。


1
我将尝试Xdebug。我以前从未使用过它,所以我必须阅读它。多谢您的回覆!希望我能尽快找到答案...
ArcticZero

34
请记住,PHP使用引用计数来管理内存。因此,如果您有循环引用或全局变量,则这些对象将不会被回收。这通常是PHP中内存泄漏的根源。
troelskn

Xdebug显示CI的Xmlrpc.php库是造成我的内存泄漏的原因。我应该知道,CodeIgniter的XML-RPC库是否有任何问题?我尝试禁用所有处理服务器端,如果我向它提供足够的数据,它仍然会耗尽内存。
ArcticZero

1
我不知道/使用CI,所以我也不知道。但是您可能应该尝试找到使用后没有释放的对象-最有可能是由于循环引用。这是侦探工作。
troelskn

1
这是唯一建议实际解决此问题的答案。其他答案可以提高记忆力,包扎症状而忽略疾病
克里斯·贝克

56

当使用array_push将2250万条记录添加到数组中时,我一直在使用4Gphp.ini文件中的内存限制来获取大约2000万条记录的“内存用尽”致命错误。为了解决这个问题,我添加了以下语句

$old = ini_set('memory_limit', '8192M');

在文件的顶部。现在一切正常。我不知道PHP是否存在内存泄漏。那不是我的工作,也不在乎。我只需要完成我的工作,就可以了。

该程序非常简单:

$fh = fopen($myfile);
while (!feof($fh)) {
    array_push($file, stripslashes(fgets($fh)));
}
fclose($fh);

致命错误指向第3行,直到我提高了内存限制,从而消除了错误。


10
你的意思是ini_set('memory_limit', '8192M');
Gogol

2
有时间去优化诸如此类的脚本是多么的奢侈。或研究和比较并学习ETL工具或类似工具。在现实世界中,我们提高了内存余量,执行该操作,然后继续前进。
马修·波尔

45

即使memory_limit设置为in php.ini,我也不断收到此错误,并使用正确读取了该值phpinfo()

通过对此进行更改:

memory_limit=4G

对此:

memory_limit=4096M

这纠正了PHP 7中的问题。


23

当您看到上述错误时-尤其是如果(tried to allocate __ bytes)a是一个较低的值,则可能表示一个无限循环,就像一个调用函数而没有出路的函数:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

启用这两行之后,它开始工作:

; Determines the size of the realpath cache to be used by PHP. This value should
; be increased on systems where PHP opens many files to reflect the quantity of
; the file operations performed.
; http://php.net/realpath-cache-size
realpath_cache_size = 16k

; Duration of time, in seconds for which to cache realpath information for a given
; file or directory. For systems with rarely changing files, consider increasing this
; value.
; http://php.net/realpath-cache-ttl
realpath_cache_ttl = 120


19

您可以通过更改memory_limitfastcgi / fpm 来正确解决此问题:

$vim /etc/php5/fpm/php.ini

将内存从128更改为512,请参见下文

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 128M

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 512M

18

您网站的根目录:

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

1
这对我有用。爱一线解决方案。+1为简单起见
Steve C

14

更改php.ini文件中的内存限制,然后重新启动Apache。重新启动后,运行phpinfo();。来自任何PHP文件的功能以进行memory_limit更改确认。

memory_limit = -1

内存限制-1表示没有设置内存限制。现在达到最大。


13

对于Drupal用户,此Chris Lane的回答是:

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

可以,但是我们需要在开幕之后放

<?php

网站根目录中index.php文件中的标记。


13

在Drupal 7中,您可以在站点/默认文件夹中的settings.php文件中修改内存限制。在260行附近,您会看到:

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

即使您的php.ini设置足够高,但如果您的Drupal settings.php文件中未设置该值,您将也不会消耗超过128 MB的内存。


1
在Drupal7中不存在settings.php中没有这样的代码字符串
FLY

在drupal 6中,settings.php中也没有字符串
AllisonC

12

如果您的代码中有一部分可能占用大量内存,则无需更改文件中的memory_limit值,而是php.ini可以删除该memory_limit部分运行之前的,然后在之后运行。

$limit = ini_get('memory_limit');
ini_set('memory_limit', -1);
// ... do heavy stuff
ini_set('memory_limit', $limit);

7

PHP 5.3+允许您通过将.user.ini文件放置在文件public_html夹中来更改内存限制。只需创建上面的文件并在其中输入以下行:

memory_limit = 64M

某些cPanel主机仅接受此方法。


7

崩溃页面?

在此处输入图片说明

(这发生在MySQL必须查询大行时。默认情况下,memory_limit将其设置为small,这对于硬件而言更安全。)

您可以在增加之前检查系统现有的内存状态php.ini

# free -m
             total       used       free     shared    buffers     cached
Mem:         64457      63791        666          0       1118      18273
-/+ buffers/cache:      44398      20058
Swap:         1021          0       1021

在这里,我将其添加为以下内容,然后做service httpd restart以解决崩溃页面的问题。

# grep memory_limit /etc/php.ini
memory_limit = 512M

在运行free -m命令确定新的memory_limit 后应该看哪个数字(行和列?)?
kiradotee

7

只需ini_set('memory_limit', '-1');在网页顶部添加一行即可。

您可以根据需要将内存设置为-1到16M等。


6
这似乎与许多现有答案说的一样。最好仅在新材料提供新颖内容的情况下,才对热门问题添加答案。
半夜

6

对于那些不知所措的人来说,为什么这个小功能会导致内存泄漏,有时是由于一个小错误,一个功能会永远递归调用。

例如,代理类与要代理它的对象的功能具有相同的名称。

class Proxy {

    private $actualObject;

    public function doSomething() {

        return $this->actualObjec->doSomething();
    }
}

有时您可能会忘记带那个实际的Objec小成员,并且由于代理实际上具有该doSomething方法,因此PHP不会给您任何错误,并且对于大型类,它可能会隐藏几分钟,以找出原因。正在泄漏内存。


另一个提示:您可以放入die('here')代码中并移动该语句,以查看递归的开始位置。
toddmo

6

在小于以前工作的数据集上运行时,出现以下错误。

致命错误:在173行的C:\ workspace \ image_management.php中,已用完的内存大小为134217728字节(试图分配4096字节)

在寻找故障的过程中,我想提一提这并不是以前答案中的技术解决方案,而是更简单的解决方案。就我而言,它是Firefox。在运行程序之前,它已经使用了1,157 MB。

事实证明,在过去的几天里,我一次只能观看50分钟的视频,这使事情变得一团糟。这是专家甚至根本没有考虑过就纠正的一种修复方法,但是对于我这样的人来说,值得牢记。


我今天在Google Chrome浏览器上也遇到过类似情况。我对这个答案非常怀疑...但是,它确实显示出我打开隐身窗口并再次触发相同脚本后,字节耗尽消失了!研究还在继续。
mickmackusa

2

像这样运行脚本(例如cron情况):php5 /pathToScript/info.php会产生相同的错误。

正确的方法: php5 -cli /pathToScript/info.php


2

如果运行的是WHM驱动的VPS(虚拟专用服务器),则可能会发现您没有直接编辑PHP.INI的权限。系统必须这样做。在WHM主机控制面板中,转到服务配置PHP配置编辑器,然后进行以下修改memory_limit

在WHM 11.48.4上更新memory_limit


2

当包含或要求包含在文件中_dbconnection.php__functions.php在实际处理的文件中而不是包含在标头中时,我发现它很有用。本身包含在内。

因此,如果包含了页眉页脚,只需在包含页眉之前先包含所有功能文件。


2

使用yield也可能是一个解决方案。请参见生成器语法

PHP.ini有时不执行更改yield内部循环的操作即可解决此问题,而无需更改文件以获取更大的内存。yield的作用不是一次转储所有数据,而是一次一读,节省了大量内存。


2
PHP.ini?是不是php.ini
彼得·莫滕森

1

该错误有时是由PHP代码中的错误引起的,该错误导致涉及异常处理和其他可能操作的递归。不幸的是,我无法创建一个小例子。

在这些情况下,这对我来说已经发生了好几次,但都set_time_limit失败了,并且浏览器一直试图通过无限循环或致命错误消息(此问题的主题)来加载PHP输出。

通过添加来减少允许的分配大小

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

在代码的开头附近,您应该能够避免发生致命错误。

然后,您可能会遇到一个终止的程序,但是仍然很难调试。

此时,BreakLoop()在程序内部执行insert 调用以获得控制权,并找出导致程序出现问题的循环或递归。

BreakLoop的定义如下:

function BreakLoop($MaxRepetitions=500,$LoopSite="unspecified")
    {
    static $Sites=[];
    if (!@$Sites[$LoopSite] || !$MaxRepetitions)
        $Sites[$LoopSite]=['n'=>0, 'if'=>0];
    if (!$MaxRepetitions)
        return;
    if (++$Sites[$LoopSite]['n'] >= $MaxRepetitions)
        {
        $S=debug_backtrace(); // array_reverse
        $info=$S[0];
        $File=$info['file'];
        $Line=$info['line'];
        exit("*** Loop for site $LoopSite was interrupted after $MaxRepetitions repetitions. In file $File at line $Line.");
        }
    } // BreakLoop

$ LoopSite参数可以是代码中函数的名称。确实没有必要,因为您将收到错误消息,将您指向包含BreakLoop()调用的行。


-1

就我而言,这是函数编写方式的一个简短问题。将新值分配给函数的输入变量可能导致内存泄漏,例如:

/**
* Memory leak function that illustrates unintentional bad code
* @param $variable - input function that will be assigned a new value
* @return null
**/
function doSomehting($variable){
    $variable = 'set value';
    // Or
    $variable .= 'set value';
}

-6

当我从代码中删除以下行时,一切正常!

set_include_path(get_include_path() . get_include_path() . '/phpseclib');
include_once('Net/SSH2.php');
include_once('Net/SFTP.php');

这些行包含在我正在运行的每个文件中。当一个一个地运行文件时,一切正常,但是一起运行所有文件时,出现内存泄漏问题。不知何故,“ include_once”不包含任何内容,或者我做错了什么...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); 这将为每个具有该行的文件添加一次路径“ / phpseclib” ...因此它可以添加多次!我建议将其放在设置文件和include_once设置文件中。
Farfromunique
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.