0

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.

user1742364
  • 154
  • 1
  • 8
  • 1
    What are the dimensions and color mode of the picture? JPEG pictures are "decompressed" upon loading. And they require much more bytes in memory than on hard drive. – Alex Shesterov Dec 14 '14 at 22:02
  • The dimension is 5760 x 3240 at 24 Bit sRGB. – user1742364 Dec 14 '14 at 22:05
  • Track _real_ memory usage: `memory_get_usage(true)` — see [docs](http://php.net/manual/en/function.memory-get-usage.php) and [this question](http://stackoverflow.com/q/2290611/2170192). – Alex Shesterov Dec 14 '14 at 22:15
  • The real memory usage is 262144. Just a few kilobyte, which is not surprising since it is the first statement in the file. However, the picularity is that PHP dies at about 64MB although the memory limit lies at 120 MB. That's the question. – user1742364 Dec 15 '14 at 16:08

1 Answers1

1

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.)

Tom Robinson
  • 1,850
  • 1
  • 15
  • 14