user1742364
user1742364

Reputation: 154

Out of memory although memory_limit is large enough

consider the following simple PHP-Script:

<?php
print memory_get_usage()."<br />";
print ini_get("memory_limit")."<br />";
$file = imagecreatefromjpeg("image.jpg");
?>

The output is the following:

109848
120M

Fatal error: Out of memory (allocated 63700992) (tried to allocate 23040 bytes) in /homepages/13/d444038670/htdocs/bilderarchiv/test.php on line 4

The picture that I try to read is a large picture. However, the second line states that the memory_limit is 120 MB, but the script dies at an allocation of about 64 MB. How can this be? The script is running perfectly on another provider, although the memory_limit is 120M there as well.

Upvotes: 0

Views: 640

Answers (1)

Tom Robinson
Tom Robinson

Reputation: 1910

You are running out of memory, but there is a solution.

Try running this on both your servers, to determine how much memory is needed per image pixel:

    <?php
    $mem0 = memory_get_usage(true);
    $megapix = imagecreatetruecolor(1000,1000);
    $mem1 = memory_get_usage(true);
    $memdif = $mem1 - $mem0;
    $perpixel = $memdif / (1000 * 1000);
    echo "<pre>1 million pixel memory test
    before imagecreate: $mem0
     after imagecreate: $mem1
     image memory used: $memdif
       bytes per pixel: $perpixel";
    ?>

I got these results:

    1 million pixel memory test  (Linux)
    before imagecreate: 524288
     after imagecreate: 5505024
     image memory used: 4980736
       bytes per pixel: 4.980736

    1 million pixel memory test (Windows)
    before imagecreate: 262144
     after imagecreate: 5505024
     image memory used: 5242880
       bytes per pixel: 5.24288

At 5 bytes per pixel, your 5760x3240 image will need 89MB.

To see if imagecreatefromjpeg needs a lot of temporary memory beyond the 89MB needed for the image, compare memory_get_usage with memory_get_peak_usage just after you load the image. In my testing, there wasn't a significant.

(Older versions of GD used 4 bytes I think.)

Next, find out how much memory you've really got:

    <?php
    echo 'memory_limit ??? ', ini_get('memory_limit'), '<br>';
    $megs = Array();
    for ( $i=0; $i < 1000; ++$i ) {     // try up to 1000MB
        $megs[] = str_repeat('*', 1048000);
        $mb= round(memory_get_usage(true) / 1024/1024);
        echo "$mb "; 
        flush();
        ob_flush();
    }
    ?>

If you get no output at all, there is probably buffering going on that you can't disable, so just try different upper limits in the for loop until you find the largest one that still works.

One Solution

I gave up long ago on GD for scaling down large jpeg images, and use ImageMagick instead. If you execute it from within PHP, it is a separate process so the PHP memory limit no longer applies. Of course there is ultimately a memory limit, but you can tell ImageMagick the maximum memory to use.

(I also got better-quality images than with GD.)

Upvotes: 1

Related Questions