用过GD库的同学可能都知道,使用imagecreatetruecolor()函数创建一个真彩色的画布是第一步。但是,如果画布的宽高超过平常的宽高,会带来极大的内存消耗。比如,一个9600×4800的画布,会带来190M的内存消耗。这时,如果服务器的free空间过小,就会导致内存耗尽,出现各种报错。本文旨在提供优化服务器时对大图片的处理方法。
首先,说下业务场景。我要对用户上传的图片进行裁剪,变成我想要的宽高比。注意,是2:1这种宽高比。 因为用的服务器内存总共只有512M,处理小图片时还好,但是一旦接触到4M以上的图片文件,内存耗尽就成了一个block的点。它会引发nginx报502的错误,因为nginx无法从php-fpm那里获取到相应的值。报错日志:a client request body is buffered to a temporary file。3119133 recv() failed (104: Connection reset by peer) while reading response header from upstream 这里可以提供下,我使用GD库对图片进行处理时的内存占用情况的日志:
获取大小内存-1 376.12 kb 获取大小内存 4.98 mb #这里使用了imagecreatetruecolor 获取大小内存2 192.53 mb 图片9600height4800 获取大小内存3 287.92 mb 获取大小内存4 287.92 mb 获取大小内存5 287.92 mb 获取大小内存6 100.38 mb 获取大小内存7 104.48 mb #这里实行了最后一步,释放内存 获取大小内存+1 376.21 kb
可以看到,很明显的内存占用,关于图片宽高对内存的影响,网上有个公式:
(width*height)* 3 * 图片位数 //乘以3是因为创建的是rgb色彩模式的图像,有3个通道
可以看到,这仅仅是一个4M的图片,就对服务器提出了将近200M的消耗。当然这里不能仅仅用大小size来衡量,还要加入Width和Height来度量实际的大小。这也是我们处理图片上传时,为什么不仅要加入大小的限制 ,还要加入宽高的限制的原因所在。 我的解决方法是使用了一个第三方软件:imagemagick。 这里我要强推下这个软件,他可以把你的多张图片合成一个pdf,也可以将一个pdf转换成多张图片,而且可以对图片增加诸如炭笔,油画等特效。
#CentOs安装方法 yum install ImageMagick #测试安装成功 convert -v
因为是我个人使用,所以直接在upload的时候实时执行了以下命令。
$command = "convert -resize *x* 'images/a.jpg' 'images/a.jpg'"; $result = exec($command, $res, $code); #这里直接使用php的exec命令即可。对参数进行下简单说明。 #convert imagemagick的转换命令 #-resize 要执行的命令 #*x* 宽乘以高,这个是小写的x #*.jpg 原图位置 #*.jpg 转换后图片的名称,不改则默认覆盖原图
加上之后,内存的占用日志
获取大小内存-1 384.83 kb 获取大小内存 384.97 kb 获取大小内存+1 385.17 kb 执行命令convert -resize 3696x1848! images/20190213094940_940.jpg images/20190213094940_940.jpg #这里在高这里加上!是表示不接受imagemagick默认的等比缩放,强制转换成这个大小
可以看到,处理速度和内存占用都降了下来,这一步,将内存的压力转换成了Cpu的压力。