Java imageio memory leak

I have two Java applications that use a ton of memory, and both use ImageIO.write (). So far, this is the only thing I have found between them.

One resizes images in a loop. Another loads the images in a loop and saves them to disk. Here is the relevant code:

one)

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 the 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 the ram concert. And he is not released when the cycle is completed. In both cases, swing gui works for me. When image saving is completed, and gui is just idle, the program still sometimes uses 1 Gb + memory. I got to the point that every variable not used directly by swing gui, is null after the loop. No effect.

What am I missing?

Thanks in advance for your help.

Additional Information: I just profile application 1 in my IDE (Netbeans). I chose the application alone because it only deals with ImageIO (and not the IO network), so this is a more controlled experiment.

While the program was doing its job (resizing images in a loop), Total Memory was between about 900,000,000 ~ 1,000,000,000 bytes, while used memory was reduced from about 30% to 50% of the total memory used for a given moment.

And the time spent at GC never exceeded 1%.

As soon as the actual resizing ended and the program turned to β€œidle”, two things happened: 1) Total Memory stopped fluxing and remained static at 1,044,054,016 bytes and 2) Used memory dropped to ~ 14,000,000 bytes (14 mb )

So, it looks like the JVM just doesn't return the memory space that it no longer uses.

I agree? Or am I reading this result incorrectly?

+4
source share
4 answers

I have something similar, and when I look at the allocated memory, I see several large blocks of memory (about 10-20 MB each) that will not be released. Looking at them with a VirtualVM memory dump, it seems that they are marked as β€œowned” by imageIO JpegImageReader. In this case, the GC will not clear them, since they are marked as being used by an external GNI call (JpegImageReader). and theJpegImageReader is long gone, so they just stay there.

In my case, this happens randomly. I suspect that this should be done when there are many calls in parallel (from several threads), or when there is an internal exception inside ImageReader, it will not release its memory, but it is not 100% sure. (and yes, I clear the buffered images, delete the reader and close the streams. It doesn't seem to help).

+5
source

What am I missing? Understanding how Java garbage collection works; -)

The memory will not be immediately released, it will be released only after the garbage collection starts. You can call GC if you want. Also, your OS plays a role - for example, Unix systems usually do not free memory, even if you free it (in C ++ terms).

0
source

You should use .flush() in a BufferedImage , which can no longer be used.
For example, in your 2nd code:

 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(); } 
0
source

I believe that you are missing Image # flush () in both cases in # 1 and # 2. I suggest you call flush () inside the finally clause. In # 2, to be on the safer side, call in.close () inside the finally clause, because if you push an exception before this line, then most likely it will not be closed based on the code snippet you inserted.

0
source

Source: https://habr.com/ru/post/1501420/


All Articles