[英]java imageio memory leak
我有兩個Java應用程序都使用大量內存,並且都使用ImageIO.write()。 到目前為止,這是我在兩者之間找到的唯一共識。
一個循環中的圖像大小調整。 另一個循環下載圖像並將其保存到磁盤。 這是相關的代碼:
1)
for(File imageFile : imageFilesList)
{
if(!stillRunning) return;
File outputFile = new File(imageFile.getAbsolutePath().replace(sourceBaseFolder.getAbsolutePath(), destinationFolder.getAbsolutePath()));
try
{
outputFile.mkdirs();
BufferedImage inputImage = ImageIO.read(imageFile);
BufferedImage resizedImage = ImageResizer.resizeImage(inputImage, maxHeight, maxWidth);
ImageIO.write(resizedImage, "jpg", outputFile);
}
catch(IOException ex)
{
userInterface.displayMessageToUser("IOException ocurred while converting an image: " + ex.getLocalizedMessage());
System.out.println(outputFile.getAbsolutePath());
ex.printStackTrace();
return;
}
imagesConverted++;
userInterface.updateTotalConvertedImages(++convertedFiles);
}
2)(在循環內)
try
{
u = new URL(urlString);
uc = u.openConnection();
uc.addRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
uc.connect();
uc.getInputStream();
in = uc.getInputStream();
BufferedImage tempImage = ImageIO.read(in);
String fileName = fn = ImageDownload.getFileName(u.getPath());
fileName = outputDirString + FILE_SEPARATOR + fileName;
while (new File(fileName).exists())
{
fileName = appendCopyIndicator(fileName);
}
ImageIO.write(tempImage, "jpg", new File(fileName));
parent.notifyOfSuccessfulDownload(fn);
in.close();
}
catch (FileNotFoundException ex)
{
parent.notifyOfFailedDownload(fn);
}
catch (IOException ex)
{
parent.handleException(ex);
}
在這兩種情況下,程序都使用大量內存。 就在一堆RAM之前。 並且當循環結束時它不會被釋放。 在這兩種情況下,我都有一個搖擺gui跑。 當圖像保存完成並且gui剛剛空閑時,程序仍然使用有時1Gb +的內存。 我已經把循環之后沒有被swing gui直接使用的每個變量設置為null
。 沒有效果。
我錯過了什么?
在此先感謝您的幫助。
更多信息:我只是在我的IDE(Netbeans)中分析了應用程序1。 我選擇了應用程序一,因為它只處理ImageIO(而不是網絡IO),因此它是一個更受控制的實驗。
當程序正在做它的事情(在循環中調整圖像大小)時,總內存在大約900,000,000~1,000,000,000字節之間徘徊,而使用的內存在給定時刻使用的總內存的大約30%到50%之間流動。
在GC中花費的時間從未超過1%。
一旦實際調整大小完成並且程序進入“空閑”狀態,就會發生兩件事:1)總內存停止流動並保持靜態為1,044,054,016字節,以及2)已用內存下降到~14,000,000字節(14 mb) 。
因此,看起來JVM不會回饋它不再使用的內存空間。
同意? 或者我誤讀了這個結果?
我有類似的東西,當我查看分配的內存時,我看到幾個大塊的內存(每個約10-20 MB)將無法釋放。 使用VirtualVM內存轉儲查看它們內部,似乎它們被imageIO JpegImageReader標記為“擁有”。 在這種情況下,GC不會清除它們,因為它們被標記為外部GNI調用(JpegImageReader)使用。 並且theJpegImageReader早已不復存在,所以他們會留在那里。
就我而言,它是隨機發生的。 我懷疑當有多個並行調用(來自多個線程)時,或者當ImageReader中存在內部異常時,它不會釋放其內存,但不是100%肯定。 (是的,我會刷新緩沖的圖像,處理讀取器,關閉流。似乎沒有幫助)。
我錯過了什么? 了解Java垃圾收集的工作原理;-)
內存不會立即釋放,只有在垃圾收集運行后才會釋放。 如果您願意,可以明確地調用GC。 你的操作系統也起了作用 - 例如,即使你釋放它,用Unix系統通常也不會釋放內存(用C ++術語)。
你應該在BufferedImage
上使用.flush()
不再可用。
例如,在您的第二個代碼中:
try
{
u = new URL(urlString);
uc = u.openConnection();
uc.addRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
uc.connect();
uc.getInputStream();
in = uc.getInputStream();
BufferedImage tempImage = ImageIO.read(in);
String fileName = fn = ImageDownload.getFileName(u.getPath());
fileName = outputDirString + FILE_SEPARATOR + fileName;
while (new File(fileName).exists())
{
fileName = appendCopyIndicator(fileName);
}
ImageIO.write(tempImage, "jpg", new File(fileName));
// release internal buffered memory
tempImage.flush();
parent.notifyOfSuccessfulDownload(fn);
in.close();
}
我相信你在#1和#2的兩種情況下都缺少Image#flush()。 我建議你在finally子句中調用flush()。 在#2中,為了更安全,請在finally子句中調用in.close(),因為如果在該行之前遇到異常,則很可能不會根據您粘貼的代碼段關閉它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.