在工作中,我們有一些tomcat服務器運行幾個webapps,其中大約一半需要做一些圖像處理。如何用ImageIO插件解決OutOfMemoryError問題?
在進行圖像處理之前,這些webapp會執行ImageIO.scanForPlugins()
以將合適的圖像讀取器和寫入器存儲到內存中。雖然之前這只是運行任何時候需要處理圖像,我們現在只有在webapps初始化時才運行掃描(因爲我們不會在運行後添加任何jar,爲什麼不止一次運行掃描?)
幾天後,由於OutOfMemoryError
,tomcat實例崩潰。幸運的是我們設置了HeapDumpOnOutOfMemoryError
選項,所以我查看了堆轉儲。在轉儲中,我發現97%的內存是由javax.imageio.spi.PartialOrderIterator
的實例拍攝的。大部分空間被支持java.util.LinkedList
,其中有1800萬元。鏈表由javax.imageio.spi.DigraphNode
組成,其中包含由ImageIO.scanForPlugins()
加載的圖像閱讀器和編寫器。
「啊哈」,我想,「我們必須在某處循環運行掃描,而我們只是一遍又一遍地添加相同的元素。但是,我想我應該仔細檢查這一假設,所以我寫了下面的測試類:
import javax.imageio.ImageIO;
public class ImageIOTesting {
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
ImageIO.scanForPlugins();
if (i % 1000 == 0) {
System.out.println(Runtime.getRuntime().totalMemory()/1024);
}
}
}
}
然而,當我在服務器環境中運行這個類,內存使用量永遠不會改變!
快速挖掘javax.imageio包的源代碼表明掃描檢查服務提供程序是否已經註冊,如果是這樣,它在註冊新提供程序之前註銷舊提供程序。所以現在的問題是:爲什麼我有這個巨大的服務提供商鏈接列表?爲什麼他們存儲爲有向圖?更重要的是,我如何防止這種情況發生?
我很欣賞評論。 這顯然是內存泄漏,但這不是開發人員在我的工作場所所能夠訪問的內容;具有巨大鏈接列表的類是javax.imageio.spi包的私有包,它隨JDK一起提供。我問是否有人知道造成這種內部泄漏的原因。 我很想使用VisualVM,但這些機器上的安全策略禁止使用jstatd,所以我無法遠程連接到它們以使用VisualVM(與VisualVM一樣好)。 – Kane
您能否指定jdk/jre版本?我想重現錯誤 –
Sun JDK 1.6.0_33,在Fedora 12盒子上運行。 – Kane