ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

128M 是 php.ini 中的默认值,但我认为这是一个很大的数字。事实上,我什至尝试过将此值设置为 1024M,但它所做的只是需要更长的时间才能出错。

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

我有点困惑......错误发生在哪里 - 在客户端或服务器中?在哪个阶段......客户端发送,服务器接收,服务器处理,服务器发送,客户端接收或客户端处理?
该错误似乎发生在客户端发送期间或服务器接收期间。我尝试禁用所有服务器端处理,并操纵它以发送预设响应,而不管发送的数据如何。如果我发送一定数量的数据,则会发生错误。我正在更改 PHP.ini 设置。
内存限制为 128MB,将其优化:ini_set('memory_limit', '256M');
摘要对所有“忽略泄漏”的答案、将 CodeIgniter 与 Drupal 混淆的人以及只是复制和粘贴其他人的答案以获得积分的人都投了反对票。这个答案的质量很糟糕。

H
Hassaan

memory_limit 更改为 ini_set('memory_limit', '-1');不是合适的解决方案。请不要那样做。

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

您可能应该尝试追踪代码中的违规代码并修复它。


@Jeff 您可能在 95% 的情况下都是对的。但是,有时您确实需要更多内存。例如,假设您的应用程序正在将大量数据加载到内存中进行处理(例如包含 15k 个组件的物料清单)。代码并不总是有问题,有时您只需要多一点内存(例如 256M 而不是 128M)。但是我同意将其设置为 -1 非常糟糕。但是在运行时为合理的情况调整内存限制是完全可以接受的恕我直言。
@pyrite是的,你是对的,有时一个进程需要更多内存,但你应该将内存限制增加到一些逻辑量,如你所说的 256MB 或 512MB 为什么不但不是 -1 ;)
@jeff 我完全同意,-1 的值可能在开发环境中用于测试目的。
@Pyrite 在您为剩余 5% 命名的情况下,以块的形式读取数据并使用工作人员来处理它,而不是使用更多内存。此解决方案也将扩展,而您的建议将不起作用,除非随着时间的推移,如果数据增长,您会不断将越来越多的内存填充到您的服务器中。
以最常见的方式,当您尝试获取更多 php 内存限制的所有数据时,ORM 中的这种麻烦。例如,当您尝试生成月度报告时。
h
hakre

ini_set('memory_limit', '-1'); 覆盖默认的 PHP memory limit


@威廉卡斯韦尔; -1 是 PHP 在此上下文中理解为 unlimited 的值。
@ArseniuszŁozicki - 它还会消耗服务器无法节省的资源。
很遗憾,这得到了这么多的赞成票。当人们需要更多内存时,使用 php.ini 编辑或 ini_set 将其设置为准确的值是一个完全有效的解决方案。将其设置为无限制是一种危险的黑客攻击:(
@user1767586 然后将其设置为合理的值。您可以通过将其设置为 1024M 来防止脚本抛出错误。如果这个答案说 ini_set('memory_limit', '1024M');你可以复制粘贴就可以了。通过将其设置为 -1,您将自己设置为拥有一个消耗所有内存的脚本。特别是如果你经常这样做。将“危险”放在引号中并不会降低危险。你真的可以软管你的主机服务器。也许开始破坏数据。我不知道,也许你会失业?对我来说听起来很危险。 :|
很遗憾看到 +161 票和 -3 票的答案是一样的:(
T
Thusitha Sumanadasa

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

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

如果您知道为什么需要这么多,并且您希望将其设置为 memory_limit = 512M 或更高,那么您应该很好。


老实说,如果您缓存了大量数据,这是正确的答案。对于某些脚本,128M 是不够的。 512M 或 1024M 通常就足够了,但您必须根据具体情况来决定。
是的,但是如果用户数量会更多,请尽量避免使用大量内存
memory_limit = -1 ;在 php.ini 中设置
@YumYumYum 这删除了memory_limit,只有在您以其他方式监视内存使用情况时才需要它。如果操作系统在某个时间点占用大量内存,操作系统将终止该进程。
所以如果你正在运行一个使用大量内存的脚本,但你只需要运行一次,你是否可以在执行时增加进程的内存限制,然后在你的一次性之后再次降低你的内存限制脚本运行?
L
Luke Stevenson

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

永久

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

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

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

暂时的

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


谢谢我没想到检查是否有人在 .htaccess 中设置了覆盖 php.ini 的值,我不知道为什么 +1
对于需要使用命令临时设置的任何人:php -d memory_limit=256M your_php_file.phpphp -d memory_limit=256M artisan ...
t
troelskn

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


我去试试Xdebug。我以前从未使用过它,所以我必须阅读它。感谢您的回复!希望我能尽快找到这个问题的答案...
请记住,PHP 使用引用计数来管理内存。因此,如果您有循环引用或全局变量,这些对象将不会被回收。这通常是 PHP 中内存泄漏的根源。
Xdebug 显示 CI 的 Xmlrpc.php 库对我的内存泄漏负责。无论如何,我应该知道 CodeIgniter 的 XML-RPC 库是否存在任何问题?我已经尝试禁用所有处理服务器端,如果我提供足够的数据,它仍然会耗尽内存。
我不知道/使用 CI,所以我不知道。但是您可能应该尝试找到使用后未释放的对象 - 很可能是因为循环引用。这是侦探工作。
这是这里唯一建议实际解决问题的答案。其他答案会提高记忆力以包扎症状并忽略疾病。
P
Peter Mortensen

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

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

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

该程序非常简单:

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

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


你的意思是 ini_set('memory_limit', '8192M');
有时间去优化这样的脚本是多么奢侈啊。或者研究、比较和学习 ETL 工具之类的。在现实世界中,我们将内存限额提高,做事,然后继续前进。
D
Danny Beckett

即使在 php.ini 中设置了 memory_limit,并且使用 phpinfo() 正确读取的值,我也不断收到此错误。

通过改变它:

memory_limit=4G

对此:

memory_limit=4096M

这纠正了 PHP 7 中的问题。


K
Kristen Waite

当您看到上述错误时 - 特别是如果 (tried to allocate __ bytes) 是一个低值,这可能是一个无限循环的指标,就像一个函数调用自己没有出路:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

P
Peter Mortensen

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

$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

P
Peter Mortensen

您网站的根目录:

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

这对我有用。喜欢单线解决方案。 +1 为简单起见
P
Peter Mortensen

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

; 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

https://content.screencast.com/users/PKMauyra/folders/Jing/media/8afa91fd-d7da-4e62-86f4-571e457e1bf9/2013-12-05_1120.png


m
mykeels

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

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

P
Peter Mortensen

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

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

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


不在 Drupal7 中,settings.php 中没有这样的代码字符串
drupal 6的settings.php中也没有字符串
P
Peter Mortensen

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

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


这似乎与许多现有答案一样。最好仅在新材料提供新颖的内容时才添加对热门问题的答案。
s
sigmapi13

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

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

有效,但我们需要在开幕式之后放置

<?php

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


P
Peter Mortensen

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

memory_limit = -1

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


F
Farzad

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

memory_limit = 64M

一些 cPanel 主机只接受这种方法。


P
Peter Mortensen

崩溃页面?

https://i.stack.imgur.com/a2IyM.png

(当 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 后应该查看哪个数字(行和列?)?
P
Peter Mortensen

对于那些挠头想知道为什么这个小函数会导致内存泄漏的人,有时由于一个小错误,一个函数开始递归地永远调用自己。

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

class Proxy {

    private $actualObject;

    public function doSomething() {

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

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


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

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

致命错误:第 173 行 C:\workspace\image_management.php 中允许的内存大小为 134217728 字节已用尽(尝试分配 4096 字节)

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

事实证明,在几天的时间里,我一次只看一段 50 分钟的视频,结果把事情搞砸了。这是专家在没有考虑的情况下纠正的那种修复,但对于我这样的人来说,这是值得牢记的。


我今天在 Google Chrome 上也遇到了类似的情况。我对这个答案非常怀疑......但是,它确实表明在我打开一个隐身窗口并再次触发相同的脚本后,我的字节耗尽消失了!研究仍在继续。
对于那些寻找答案的人......我会跳过这个。我认为客户端机器上的 Web 浏览器(例如 chrome 或 firefox)的内存消耗与服务器机器上的 php 脚本使用的内存消耗没有任何关系。如果有人注意到在客户端发生更改时服务器内存问题消失了,那毫无疑问是巧合。这并不是说某些客户端请求很多东西可能会导致服务器(带有错误代码)的内存不足,或者客户端(带有不同的错误代码)也可能导致内存不足。
P
Peter Mortensen

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

有时在循环内实现 yield 可能会解决问题,而不是更改 PHP.ini 文件以获得更大的内存存储。 yield 所做的不是一次转储所有数据,而是一一读取,节省大量内存使用。


PHP.ini?不是php.ini吗?
D
DragonFire

在我的 mac (Catalina - Xampp) 上,没有加载文件,所以我必须先这样做。

sudo cp /etc/php.ini.default /etc/php.ini
sudo nano /etc/php.ini

然后更改 memory_limit = 512M

然后重新启动Apache并检查文件是否加载

php -i | grep php.ini

结果是

Configuration File (php.ini) Path => /etc
Loaded Configuration File => /etc/php.ini

最后检查

php -r "echo ini_get('memory_limit').PHP_EOL;"

php -r "echo ini_get('memory_limit').PHP_EOL;" 2048M 我仍然得到一个错误 Allowed memory size of 134217728 bytes exhausted (tryed to allocate 16384 bytes) 但有关尝试分配的信息是从 xx16384 到 16388 你知道为什么吗?
J
Jayme Brereton

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

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


P
Peter Mortensen

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

https://i.stack.imgur.com/kewYS.png


P
Peter Mortensen

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

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


D
David Spector

对我来说,此错误消息的最常见原因是在 PHP“for”语句中省略了“++”运算符。无论您允许使用多少内存,这都会导致循环永远继续。这是一个简单的语法错误,但编译器或运行时系统很难检测到。如果我们想寻找它,我们很容易纠正!

但是,假设您想要一个提前停止此类循环并报告错误的通用过程?您可以简单地检测每个循环(或至少是最内层的循环),如下所述。

在某些情况下,例如异常内的递归,set_time_limit 失败,并且浏览器不断尝试加载 PHP 输出,无论是无限循环还是致命错误消息,这是本问题的主题。

通过减少代码开头附近允许的分配大小,您可以防止致命错误,如其他答案中所述。

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

无论您的程序是否终止,通过在您的程序中插入 BreakLoop() 调用来检测您的代码以获得控制并找出您的程序中的哪个循环或递归导致了问题。

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() 调用的行。


P
Peter Mortensen

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

/**
* 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';
}

H
Hossein Azad

https://i.stack.imgur.com/WaUHE.png

这对服务器来说太危险了 您的 PHP 代码可能在某处存在内存泄漏,而您正在告诉服务器只使用它想要的所有内存。你根本不会解决问题。如果您监视您的服务器,您会发现它现在可能正在使用大部分 RAM,甚至交换到磁盘。


J
Juan Pablo G

我花了两个时间寻找解决方案,我发现这是我打电话时与 PDO 通话的原因

$stmt->bindParam(":PERIOD", $period); 

变量周期是

empty string ''

所以这个问题可能有多个根本原因,我对你的建议是尝试反复试验或二分法来寻找根本原因,删除代码并尝试搜索失败的行代码

更新:我使用 $pdo->query() 方法也遇到了这个错误我使用了 $pdo->prepare() 并且运行良好,所以,虽然我有

$sql = "SELECT * FROM COURSE_DETAILS where ACTIVE = 1 AND COURSE_DETAILS_ID = $id";
$stmt = getConnection()->query($sql);
$courseDetails = $stmt->fetchAll(PDO::FETCH_ASSOC)

然后我把它改成

$sql = "SELECT * FROM COURSE_DETAILS where ACTIVE = 1 AND COURSE_DETAILS_ID = ?";
$stmt = getConnection()->prepare($sql);
$stmt->execute(array($id)); 

神奇地内存错误消失了!


H
Hmerman6006

这个问题是几年前问的,所以虽然我的事实不一样,但我最近在循环解析服务器上的html表时也收到了这个错误。错误的原因是因为使用连接到变量 $table 的双引号来解析 html,同时在多行上连接字符串。

$table = "<table>\n";
    $table .= "<tbody>\n";
        foreach ($data as $item) {
            $table .= "<tr>\n";
                // this caused the Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted
                $table .= "<td>$item->description</td><td>$item->qty</td>" .  
                $table .= "<td>$item->price_incl</td><td>$item->price->vat</td>" .
                $table .= "<td>$item->price_excl</td><td>$item->available</td>" .
            $table .= "</tr>\n";
        }
    $table .= "</tbody>";
$table .= "</table>\n";

上面的错误对我来说很奇怪,但考虑到我已经将字符串连接到 $table 变量,现在我尝试过这个似乎很愚蠢。解决方案是删除第 7 行和第 8 行的变量连接或删除第 6、7 和 8 行的结束连接符号。


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅