关于php:致命错误:允许的内存大小为134217728 Bytes Exhausted(CodeIgniter + XML-RPC)

Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted (CodeIgniter + XML-RPC)

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

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

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

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

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


通过ini_set('memory_limit', '-1');更改memory_limit不是一个合适的解决方案。请不要这样做。

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

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


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


正确的方法是编辑php.ini文件。
memory_limit编辑为您的愿望值。

从您的问题来看,128M(这是默认限制)已被超出,因此您的代码存在严重错误,因为它不应该占用太多。

如果你知道它为什么需要这么多,你想让它设置memory_limit = 512M或更高,你应该是好的。


PHP的内存分配可以永久调整,也可以暂时调整。

永久性

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

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

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

临时

您可以在PHP文件中动态调整内存分配。你只需要代码ini_set('memory_limit', '128M');(或任何你想要的分配)。您可以通过将值设置为"-1"来删除内存限制(尽管可能仍适用机器或实例限制)。


在PHP脚本中很容易出现内存泄漏 - 尤其是在使用抽象时,例如ORM。尝试使用Xdebug来分析您的脚本并找出所有内存的去向。


当使用array_push向数组中添加2250万条记录时,我使用4G作为文件php.ini中的内存限制,在大约20M记录中不断出现"内存耗尽"致命错误。为了解决这个问题,我添加了声明

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

在文件的顶部。现在一切正常。我不知道PHP是否有内存泄漏。那不是我的工作,也不关心。我只需要完成我的工作,这很有效。

该程序非常简单:

1
2
3
4
5
$fh = fopen($myfile);
while (!feof($fh)) {
    array_push($file, stripslashes(fgets($fh)));
}
fclose($fh);

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


即使在php.ini中设置了memory_limit,并且使用phpinfo()正确读出值,我仍然会收到此错误。

通过改变它:

1
memory_limit=4G

对此:

1
memory_limit=4096M

这解决了PHP 7中的问题。


当你看到上面的错误 - 特别是如果(tried to allocate __ bytes)是一个低值时,这可能是一个无限循环的指示器,就像一个无法自行调用自身的函数:

1
2
3
4
function exhaustYourBytes()
{
    return exhaustYourBytes();
}

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

1
2
3
4
5
6
7
8
9
10
11
; 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

>
</p>
<div class=


您可以通过更改fastcgi / fpm上的memory_limit来正确解决此问题:

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

更改内存,如128到512,见下文

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

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

您网站的根目录:

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


对于Drupal用户,这个Chris Lane的答案是:

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

有效,但我们需要在开幕后才提出来

1
<?php

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


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

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

即使你的php.ini设置足够高,如果没有在你的Drupal settings.php文件中设置,你将无法消耗超过128 MB。


更改php.ini文件中的内存限制并重新启动Apache。重启后,运行phpinfo();从任何PHP文件中执行memory_limit更改确认。

1
memory_limit = -1

内存限制-1表示没有设置内存限制。它现在处于最大值。


如果您的代码的一部分可以使用大量内存,而不是更改php.ini文件中的memory_limit值,则可以在该部分运行之前删除memory_limit,然后将其替换。

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

崩溃页面?

Enter image description here

(当MySQL必须查询大行时会发生这种情况。默认情况下,memory_limit设置为较小,这对硬件来说更安全。)

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

1
2
3
4
5
# 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来修复崩溃页面问题。

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

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

1
memory_limit = 64M

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


对于那些摸不着头脑,找出原因,这个小函数应该导致内存泄漏的人,有时会因为一点点错误,一个函数开始递归地调用自己。

例如,一个代理类,它与要代理它的对象的函数具有相同的名称。

1
2
3
4
5
6
7
8
9
class Proxy {

    private $actualObject;

    public function doSomething() {

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

有时你可能会忘记带上那个小的actualObjec成员,因为代理实际上有那个doSomething方法,PHP不会给你任何错误,对于一个大类,它可能会隐藏在眼睛里几分钟才能找到为什么它会泄漏记忆。


我在以前工作的数据集上运行时遇到了以下错误。

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes) in C:\workspace\image_management.php on line 173

由于对故障的搜索将我带到了这里,我想我会提到它并不总是以前答案中的技术解决方案,而是更简单的东西。就我而言,它是Firefox。在我运行该程序之前,它已经使用了1,157&nbsp; MB。

事实证明,我在一段时间内一次看了50分钟的视频,这让事情搞得一团糟。这是专家在没有考虑的情况下纠正的那种解决办法,但对于我这样的人来说,值得记住。


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

Updating memory_limit on WHM 11.48.4


我发现在实际处理的文件中包含或要求_dbconnection.php__functions.php时,它很有用,而不是包含在标题中。其中包含哪些内容。

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


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

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


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

在这些情况下,已经多次发生过这种情况,set_time_limit失败,并且浏览器一直试图加载PHP输出,无论是使用无限循环还是使用致命错误消息,这是该问题的主题。

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

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

在代码开头附近,您应该能够防止致命错误。

然后你可能会留下一个终止??的程序,但仍然很难调试。

此时插入BreakLoop()调用程序内部以获得控制权并找出程序中的循环或递归导致问题。

BreakLoop的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
2
3
4
5
6
7
8
9
10
/**
* 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';
}


使用yield也可能是一种解决方案。请参阅Generator语法。

有时在循环内部实现yield可能会解决问题,而不是将php.ini文件更改为更大的内存存储。产量的作用不是一次性转储所有数据,而是逐个读取,节省了大量的内存使用量。


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

您可以根据需要在-1,16M等位置设置内存。


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

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

这些行包含在我运行的每个文件中。一个接一个地运行文件,一切正常,但是当一起运行所有文件时,我遇到了内存泄漏问题。不知何故,"include_once"不包括一次,或者我做错了什么......