imagecreatefromjpeg处理图片时内存溢出问题

  • Jesse
  • 2017-06-01 11:25:00
  • 5126
记一次上传图片内存溢出的bug

有用户反映上传图片失败,于是追根溯源发现是上传图片时内存溢出。

可是服务器配置的使用内存是128MB,上传限制是2MB,用户上传的图片只有737KB

 

继续往下看,发现在上传图片后生成缩略图时,使用imagecreatefromjpeg这个函数时报的内存溢出,

 

查看官方文档,才发现imagecreatefromjpeg在动态创建一个新图像时,根据图片的分辨率(宽和高)在内存中生成一个新图像。

恍然大悟,虽然用户上传的图片只有737KB,但分辨率却高达7088*4726,使用了159MB内存,超过128MB,很明显会内存溢出。

 

官方手册:

imagecreatefromjpeg  由文件或 URL 创建一个新图象。

imagecreatefromjpeg创建图像时占用内存公式

    总字节数 = * * 每像素所占字节数 * 其它因素

 

每像素所占字节数有2种计算方式:

    每像素所占字节数 = 位深 / 8 = 色深(bits) * 图像的通道(channels) / 8

(php使用getimagesize可以获取jpg图片的bitschannels,位深:需要在电脑上查看图片的属性->详细信息)

 

其创建新图像的动作是在内存中实现,因此图像的宽和高很大程度的决定了内存的消耗。

 

总结:在用户上传图像时除了要限制文件的大小还要限制图像的分辨率,否则可能会内存溢出。

 

至于"其它因素"可以反推算出来,例如:

<?php

header('Content-Type: text/plain');

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

function format_size($size) {
    if ($size < 1024) {
        return $size . ' bytes';
    } else {
        $size = round($size / 1024, 2);
        $suffix = 'KB';
        if ($size >= 1024) {
            $size = round($size / 1024, 2);
            $suffix = 'MB';
        }
        return $size . ' ' . $suffix;
    }
}

$start_mem = memory_get_usage();

echo 'Limit: ' . ini_get('memory_limit') . "\n";
echo 'Usage before: ' . format_size($start_mem) . "\n";

// Place the images to load in the following array:
$images = array('image1.jpg', 'image2.jpg', 'image3.jpg');
$ffs = array();

echo "\n";
foreach ($images as $image) {
    $info = getimagesize($image);
    printf('Loading image %s, size %s * %s, bpp %s... ',
    $image, $info[0], $info[1], $info['bits']);
    $im = imagecreatefromjpeg($image);
    $mem = memory_get_usage();
    echo 'done' . "\n";
    echo 'Memory usage: ' . format_size($mem) . "\n";
    echo 'Difference: ' . format_size($mem - $start_mem) . "\n";
    $ff = (($mem - $start_mem) / ($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels']));
    $ffs[] = $ff;
    echo 'Difference / (Width * Height * Bytes per pixel): ' . $ff . "\n";
    imagedestroy($im);
    $start_mem = memory_get_usage();
    echo 'Destroyed. Memory usage: ' . format_size($start_mem) . "\n";

    echo "\n";
}

echo 'Mean fudge factor: ' . (array_sum($ffs) / count($ffs));

?>

测试得出结果:

Limit: 512M

Usage before: 132.88 KB

 

Loading image image1.jpg, size 7088 * 4726, bpp 8... done

Memory usage: 159.98 MB

Difference: 159.85 MB

Difference / (Width * Height * Bytes per pixel): 1.6678853703652

Destroyed. Memory usage: 134.72 KB

 

Loading image image2.jpg, size 709 * 473, bpp 8... done

Memory usage: 1.75 MB

Difference: 1.62 MB

Difference / (Width * Height * Bytes per pixel): 1.6886203856388

Destroyed. Memory usage: 134.8 KB

 

Loading image image3.jpg, size 1024 * 768, bpp 8... done

Memory usage: 3.91 MB

Difference: 3.77 MB

Difference / (Width * Height * Bytes per pixel): 1.6776224772135

Destroyed. Memory usage: 134.88 KB

Mean fudge factor: 1.6780427444059


本文出自 亮有一技,转载时请注明出处及相应链接。