BufferedImage記憶體洩漏和溢位問題

翎野君發表於2024-05-03

java的ImageIO處理圖片

在使用Thumbnailator時出現了OOM問題,但是其使用方法只有一行程式碼,無法針對其內部使用的物件進行資源釋放,所以使用原生的Java類庫中ImageIO來處理圖片。 關鍵有三個類:ImageIO、BufferedImage、Graphics

  • ImageIO類包含兩個靜態方法:read()和write(),透過這兩個方法即可完成對點陣圖檔案的讀寫,呼叫write()方法輸出圖形檔案時需要指定輸出的圖形格式。
public static BufferedImage read(File input) throws IOException
public static boolean write(RenderedImage im,String formatName,File output)throws IOException
  • Image類代表點陣圖,但它是一個抽象類,無法直接建立Image物件,為此java為它提供了一個BufferedImage子類,這個子類是一個可以訪問影像資料緩衝區的Image實現類。該類提供了一個簡單的構造器:BufferedImage(int width,int height,int imageType):建立指定大小、指定影像型別的BufferedImage物件。除此之外,還提供一個getGraphics()方法返回該物件的Graphics物件,從而允許透過該Graphics物件向BufferedImage中新增圖形。
  • Graphics是一個抽象的畫筆物件,它可以在元件上繪製豐富多彩的幾何圖形和點陣圖。它提供有一個重要方法,將一個img物件的原始圖形寬度縮小為width,高度縮小為height,新增到BufferedImage物件的(x,y)處:public abstract boolean drawImage(Image img, int x, int y,int width,int height, ImageObserver observer)

關鍵的畫素位乘積可能導致記憶體暴漲以至出現OOM

BufferedImage.java:324,DirectColorModel.java:1032,Raster.java:467,DataBufferInt.java:75

至此可以得知,提示OOM的原因為圖片的寬度和高度的畫素乘積過大導致在初始化int的陣列的時候出現 java.lang.OutOfMemoryError: Java heap space。

BufferedImage的一些坑

BufferedImage的一些坑:

  • 專案中,BufferedImage的讀取載入流程是:下載圖片 -> 透過ImageIO.read()轉成BufferedImage。很有可能的是,下載的圖片過大,那麼轉成BufferedImage的物件也會很大。
  • 此外BufferedImage儲存的內容是不經過壓縮的,你本地磁碟上讀取了一個圖片檔案,轉成BufferedImage物件後,大小可能是檔案大小的數倍。這是因為BufferedImage的物件大小是要按照點陣圖那一套演算法計算的,即畫素數 * 單個畫素儲存大小。一般專案中都是用彩圖,即24位。
    • 一個例子:一張1200 * 900的彩圖A和黑白圖B,大小分別為800KB和100KB,均為JPG格式,但是讀到記憶體裡後,大小變為了3MB多,這是因為它們都用彩圖儲存(ImageIO.read()就是這麼處理的),且size = 1200 * 900 * 24 / 8 = 3240000 bytes

所以當要快取圖片或者大物件(包含大量位元組串)的時候,可以考慮:

  • 對物件進行壓縮(顯然BufferedImage壓縮比較困難,可以用第三方庫?)
  • 另外我認為,對於影像的快取(或者是大的byte[]物件),應該利用磁碟快取或者用類似Redis那樣的快取,而不是儲存在本機記憶體裡

結論

  • 1、java對於圖片的處理技術在處理小圖片時,完全夠用,但是在處理大於1MB以上的圖片時,就不再推薦本身伺服器去處理圖片。
  • 2、有條件的還是將圖片的處理交給第三方來,呼叫封裝好的API等來處理圖片的各種要求。

參考連結

https://keys961.github.io/2018/05/28/JVM%E5%A0%86%E5%86%85%E5%AD%98%E5%88%86%E6%9E%90/

https://blog.csdn.net/calm_encode/article/details/120427312

https://juejin.cn/post/6844903892543602702

https://blog.csdn.net/loophome/article/details/101773866

本篇文章如有幫助到您,請給「翎野君」點個贊,感謝您的支援。

首發連結:https://www.cnblogs.com/lingyejun/p/18156503

相關文章