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

Viewed 1755697

I have a bunch of client point of sale (POS) systems that periodically send new sales data to one centralized database, which stores the data into one big database for report generation.

The client POS is based on PHPPOS, and I have implemented a module that uses the standard XML-RPC library to send sales data to the service. The server system is built on CodeIgniter, and uses the XML-RPC and XML-RPCS libraries for the webservice component. Whenever I send a lot of sales data (as little as 50 rows from the sales table, and individual rows from sales_items pertaining to each item within the sale) I get the following error:

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

128M is the default value in php.ini, but I assume that is a huge number to break. In fact, I have even tried setting this value to 1024M, and all it does is take a longer time to error out.

As for steps I've taken, I've tried disabling all processing on the server-side, and have rigged it to return a canned response regardless of the input. However, I believe the problem lies in the actual sending of the data. I've even tried disabling the maximum script execution time for PHP, and it still errors out.

33 Answers

It's very easy to get memory leaks in a PHP script - especially if you use abstraction, such as an ORM. Try using Xdebug to profile your script and find out where all that memory went.

After enabling these two lines, it started working:

; 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

Rather than changing the memory_limit value in your php.ini file, if there's a part of your code that could use a lot of memory, you could remove the memory_limit before that section runs, and then replace it after.

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

Change the memory limit in the php.ini file and restart Apache. After the restart, run the phpinfo(); function from any PHP file for a memory_limit change confirmation.

memory_limit = -1

Memory limit -1 means there is no memory limit set. It's now at the maximum.

Just add a ini_set('memory_limit', '-1'); line at the top of your web page.

And you can set your memory as per your need in the place of -1, to 16M, etc..

Using yield might be a solution as well. See Generator syntax.

Instead of changing the PHP.ini file for a bigger memory storage, sometimes implementing a yield inside a loop might fix the issue. What yield does is instead of dumping all the data at once, it reads it one by one, saving a lot of memory usage.

In my case on mac (Catalina - Xampp) there was no loaded file so I had to do this first.

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

Then change memory_limit = 512M

Then Restart Apache and check if file loaded

php -i | grep php.ini

Result was

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

Finally Check

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

The most common cause of this error message for me is omitting the "++" operator from a PHP "for" statement. This causes the loop to continue forever, no matter how much memory you allow to be used. It is a simple syntax error, yet is difficult for the compiler or runtime system to detect. It is easy for us to correct if we think to look for it!

But suppose you want a general procedure for stopping such a loop early and reporting the error? You can simply instrument each of your loops (or at least the innermost loops) as discussed below.

In some cases such as recursion inside exceptions, set_time_limit fails, and the browser keeps trying to load the PHP output, either with an infinite loop or with the fatal error message which is the topic of this question.

By reducing the allowed allocation size near the beginning of your code you might be able to prevent the fatal error, as discussed in the other answers.

Then you may be left with a program that terminates, but is still difficult to debug.

Whether or not your program terminates, instrument your code by inserting BreakLoop() calls inside your program to gain control and find out what loop or recursion in your program is causing the problem.

The definition of BreakLoop is as follows:

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

The $LoopSite argument can be the name of a function in your code. It isn't really necessary, since the error message you will get will point you to the line containing the BreakLoop() call.

In my case it was a brief issue with the way a function was written. A memory leak can be caused by assigning a new value to a function's input variable, e.g.:

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

change ;memory_limit=512M to ;memory_limit=-1 in enter image description here

it's too dangerous for a server Your PHP code may have a memory leak somewhere and you are telling the server to just use all the memory that it wants. You wouldn't have fixed the problem at all. If you monitor your server, you will see that it is now probably using up most of the RAM and even swapping to disk.

I spent two dyas looking a solution for this and I figured out that this was cause in a call with PDO when I called

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

and the variables period was an

empty string ''

So this issue could have multiple root cause, my advice to you is that try a trial and error or a bisection method for a root cause finding, delete code and the try to search what is the line code that is failing

Update: I also faced this error with the method $pdo->query() I used $pdo->prepare() and worked well, so, while I had

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

then i changed this to

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

and magically the memory error dissapeared!

This question was asked a few years ago, so although my facts are not the same, I also received this error recently when parsing a html table on server within loop. The reason for the error was because the html was parsed using double quotes that was concatenated to a variable $table, while simultaneously concatenating strings on multiline.

$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";

The above error was strange to me, but considering that I was already concatenating the string to the $table variable it now seems foolish that I had tried this. Solution was either to remove the variable concatenation on line 7 and 8 or to remove endline concatenation symbol from line 6, 7 and 8.

In my case it was a full disk and mysql shat on itself.

After freeing up disk space, repairing the database and restarting Apache, my site worked again!

Some drive-by kiddo managed to flood my logs and fill up the scarce 500ish maybebytes I had left on the VM. :D

The reason for this error is that your server configuration has a very low memory limit. Try adding this to wp-config.php (put it after <?php in this file):

define('WP_MEMORY_LIMIT', '96M');

Please note that this limit is OK for the theme and the plugins that come with the theme. If you want to enable other plugins you may need to increase the limit further.

define('WP_MEMORY_LIMIT', '256M');
Related