I have two Java applications that both use a ton of memory, and both use ImageIO.write(). So far, that is the only thing I have found in common between the two.
One resizes images in a loop. The other downloads images in a loop and saves them to disk. Here's the relevant code:
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) (inside a loop)
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);
}
In both cases, the program uses a lot of memory. Right around a gig of RAM. And it doesn't get freed up when the loop is over. In both cases I have a swing gui running. When the image saving is all done and the gui is just idling, the program is still using sometimes 1Gb+ of memory.
I have gone so far as to set every variable not directly used by the swing gui to null
after the loop. To no effect.
What am I missing?
Thanks in advance for your help.
More information: I just profiled application 1 in my IDE (Netbeans). I chose application one because it only deals with ImageIO (and not network IO), so it's a more controlled experiment.
While the program was doing its thing (resizing images in a loop), the Total Memory hovered between roughly 900,000,000 ~ 1,000,000,000 bytes, while the Used Memory fluxuated between roughly 30% and 50% of the Total Memory being used at a given moment.
And time spent in GC never went above 1%.
As soon as the actual resizing was finished and the program went into "idle", two things happened: 1) The Total Memory stopped fluxuating and stayed static at 1,044,054,016 bytes, and 2) the Used Memory dropped to ~14,000,000 bytes (14 mb).
So, it looks like the JVM is just not giving back memory space that it's no longer using.
Agree? Or am I misreading this result?
I have something similar and when I look into the memory allocated I see several large blocks of memory (approx. 10-20 MB each) that will not be released. Looking inside them with a VirtualVM memory dump, it seems as if they are marked as "owned" by the imageIO JpegImageReader. In this case, GC will not clear them as they are marked as used by an external GNI call (the JpegImageReader). and theJpegImageReader is long gone, so they will just stay there.
In my case it happens randomly. I suspect it has to do when there are many calls in parallel (from multiple threads), or when there is an internal exception inside the ImageReader it will not release its memory, but not 100% sure. (and yes, I do flush the buffered images, dispose the reader, and close the streams. Does not seem to help).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With