解决PHP处理图片时内存占用过高问题

用过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 图片width: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的压力。