imagecreatefromjpeg处理图片时内存溢出问题
记一次上传图片内存溢出的bug
有用户反映上传图片失败,于是追根溯源发现是上传图片时内存溢出。
可是服务器配置的使用内存是128MB,上传限制是2MB,用户上传的图片只有737KB,
继续往下看,发现在上传图片后生成缩略图时,使用imagecreatefromjpeg这个函数时报的内存溢出,
查看官方文档,才发现imagecreatefromjpeg在动态创建一个新图像时,根据图片的分辨率(宽和高)在内存中生成一个新图像。
恍然大悟,虽然用户上传的图片只有737KB,但分辨率却高达7088*4726,使用了159MB内存,超过128MB,很明显会内存溢出。
官方手册:
imagecreatefromjpeg — 由文件或 URL 创建一个新图象。
imagecreatefromjpeg创建图像时占用内存公式:
总字节数 = 宽 * 高 * 每像素所占字节数 * 其它因素
每像素所占字节数有2种计算方式:
每像素所占字节数 = 位深 / 8 = 色深(bits) * 图像的通道(channels) / 8
(php使用getimagesize可以获取jpg图片的bits和channels,位深:需要在电脑上查看图片的属性->详细信息)
其创建新图像的动作是在内存中实现,因此图像的宽和高很大程度的决定了内存的消耗。
总结:在用户上传图像时除了要限制文件的大小还要限制图像的分辨率,否则可能会内存溢出。
至于"其它因素"可以反推算出来,例如:
<?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