系統頻繁Full gc問題分析及解決辦法
一、場景描述
上週開始系統在業務高峰期一直收到Full gc報警,監控顯示fgc頻繁,下圖是監控圖,左邊紅框是優化前效果,右邊是優化後,優化後fgc基本為0
二、原因查詢
1.檢視gc日誌,發現old區fgc後大小沒有變化,如下圖:
2.去線上dump記憶體看是什麼物件,用memory analyzer分析,Retained Size竟然有2.4G,全是sun.awt.SunToolkit這個物件,其實到這一步已經可以確定是什麼問題了,只是自己對系統不是很熟悉,導致定位具體的問題程式碼花了一些時間
三、原因分析
系統中有一個呼叫頻繁的介面會呼叫下面這個方法,目的是獲取圖片的寬高資訊,但是Image這個物件用完不會自動釋放,需要手動呼叫 flush()方法;以前沒有呼叫這個方法,就導致一有請求就會有大物件進入old區,在業務高峰期old區一會就被打滿,所以一直進行fgc
public static Image getImage(String path) {
ImageIcon icon = new ImageIcon(path);
Image img = icon.getImage();
return img;
}
四、解決辦法
其實不管是用Image還是BufferedImage,讀取圖片的寬高不用把圖片全部載入到記憶體,在圖片的寬高資訊其實是儲存在檔案頭中的,只 要按不同的格式讀取檔案的頭資訊就可以拿到寬高資訊
使用ImageReader程式碼如下
Iterator readers = ImageIO.getImageReadersByFormatName(StringUtil.getFileSuffix(filePath));
ImageReader reader = (ImageReader)readers.next();
iis = ImageIO.createImageInputStream(is);
reader.setInput(iis, true);
return Pair.of(reader.getWidth(0),reader.getHeight(0));