views:

699

answers:

5

I'm using a single image upload/crop/resize script for files up to 10MB.

When testing, I set php_ini memory limit to 25M and that is exhausted when uploading a file only about 1.4MB.

"Allowed memory size of 26214400 bytes exhausted (tried to allocate 10368 bytes)"

This seems strange to me, isn't 10368 < 26214400? (Rhetorical Question)

Or does that mean I went 10368 bytes over 25MB? Should my script be using this much memory?

Code:

function make_thumbnails($updir, $img)
{
    $thumbnail_width    = 200;
    $thumbnail_height   = 150;
    $thumb_preword  = "thumb_";

    $arr_image_details  = GetImageSize($updir.$img);
    $original_width = $arr_image_details[0];
    $original_height    = $arr_image_details[1];

    if( $original_width > $original_height ){
        $new_width  = $thumbnail_width;
        $new_height = intval($original_height*$new_width/$original_width);
    } else {
        $new_height = $thumbnail_height;
        $new_width  = intval($original_width*$new_height/$original_height);
    }

    $dest_x = intval(($thumbnail_width - $new_width) / 2);
    $dest_y = intval(($thumbnail_height - $new_height) / 2);

    if($arr_image_details[2]==1) { $imgt = "ImageGIF";  $imgcreatefrom = "ImageCreateFromGIF";  }
    if($arr_image_details[2]==2) { $imgt = "ImageJPEG"; $imgcreatefrom = "ImageCreateFromJPEG";  }
    if($arr_image_details[2]==3) { $imgt = "ImagePNG";  $imgcreatefrom = "ImageCreateFromPNG";  }

    if( $imgt )
    {
        $old_image = $imgcreatefrom($updir.$img);
        $new_image = imagecreatetruecolor($thumbnail_width, $thumbnail_height);
        imageCopyResized($new_image,$old_image,$dest_x,
        $dest_y,0,0,$new_width,$new_height,$original_width,$original_height);
        $imgt($new_image,$updir.$thumb_preword.$img);

        // Added by your suggestions:
         imagedestroy($old_image);
         imagedestroy($new_image);
    }
}
+2  A: 

The error message says that it tried to allocate another 10368 bytes, but it wasn't available. In other words, your 25MB pool was exhausted and the script couldn't allocate the 10368 bytes it needed.

You can increase this limit in your php.ini file, by adding or updating a line similar to the following:

memory_limit = 64M

As far as "if 25MB is enough," that is a difficult question for us to answer... There are certainly some scripts out there that legitimately need 64MB or even more. If you find that you have to constantly increase the size of your memory pool, I'd start looking into what's taking so much space.

Here is a related question that has some good discussion on the size of your memory pool.

EDIT Seeing your code posted, it is definitely possible to consume a large amount of memory when you are working with images. You can help your script by calling imagedestroy after you are done with an image resource.

jheddings
+1  A: 

That means that at the moment when you exceeded the limit, your script was trying to allocate 10368 bytes but it didn't succeed. That doesn't mean that you won't have this problem anymore if you increase the limit to 26MB. The error might occur at some later point. You might try to increase it in smaller steps (e.g. 32MB, 48MB, etc.) until you don't get this error anymore.

Tomas Markauskas
+2  A: 

Or does that mean I went 10368 bytes over 25MB?

No. Your script was trying to allocate 10368 bytes, 10368 + alreadyallocated > 25MB

Should my script be using this much memory?

If you're using GD for resizing, yes. I'd try to use other libs or console tools for image processing, they can give more perfomance. And, you can decide to use a queue for image processing and not resize images just-in-time, if it's public website

valya
I will look into this, thank you
Paul Silvis
+2  A: 

Use imagedestroy to free the memory after usage:

if( $imgt )
{
    $old_image = $imgcreatefrom($updir.$img);
    $new_image = imagecreatetruecolor($thumbnail_width, $thumbnail_height);
    imageCopyResized($new_image,$old_image,$dest_x,
    $dest_y,0,0,$new_width,$new_height,$original_width,$original_height);
    imagedestroy($old_image);
    $imgt($new_image,$updir.$thumb_preword.$img);
    imagedestroy($new_image);
}
Gumbo
Sweet, this brought my memory usage down some. I should note for others with this question, the proper syntax is imagedestroy($new_image);Thanks!
Paul Silvis
@Paul Silvis: Thanks. Fortunately PHP.net showed the right function as I actually entered `image_destroy`.
Gumbo
+8  A: 

In addition to what has been said already:

Never forget that processing compressed file formats (like JPEG) needs much more memory than the actual file size. A 3000 x 3000 Pixel JPG file can weigh only 500kb, but will require (roughly) 3000 x 3000 x 3 (One byte each for Red, Green, and Blue, and depending on mode even one more for Alpha) = at least 27 MB.

Pekka
Thank you, this really brings estimating "acceptable" efficiency into focus.
Paul Silvis
+1 I bet ran his code through a debugger, he'd bomb out at `$imgcreatefrom($updir.$img);` (if that line isn't already indicated by part of the error message he didn't paste).
timdev