用過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的壓力。