One of our customers sent in a support request regarding a memory leak which was assigned to me to investigate. It actually turned out to be rather an interesting problem and provided a fix for a bug in Sun’s own code so read on for the full details and the patched jar.
To hunt down the bug, I used the excellent JProfiler to see if it would give me a clue as to what was going on. Here is a screenshot.
It turned out that the leak was actually in one of Sun’s own JAI classes, which have not seen much development in recent years. The jpeg2000 image reader seemed to be holding on to some resources even when the reference to the J2KImageReader instance had been released in our code. In the screenshot you might be able to see there is 670 odd kilobytes and just over 15 thousand instances still referenced. I looked at the reference graph in JProfilier for some of the instances and ended going round in circles!
I decided that I would have to look at the jai-imageio code to see if there was something to be done. At this point I also realised that some of our JAI links where broken and that JAI seems to be pretty much forgotten about.
After having a look at the JAI image-io code I decided to use a pretty straight forward strategy to release the memory: set some object references to null somewhere along the line! The J2KImageReader class seemed to be the place to start. While having a look I realised that the J2KImageReader class did not implement a required dispose method. When we called dispose it was just calling the super implementation of dispose in the ImageReader class. This is an empty method with a comment saying that subclasses must implement their own dispose method. I created a dispose method, nulled out J2KImageReaders private object members, rebuilt the image-io jar and ta-da!
No more memory leak! Which was pretty cool. The next part was a bit more difficult: commiting my change back to the jai-image-io repository, I faffed around for too long trying to see if this is still possible. In the end I gave up! I heard a rumour that the guy administrating the code does not work for Sun/Oracle any more, but if you have had any success comitting your changes to some of the old projects hosted on java-net then please drop me a line.
Anyway, if you are having the same problems with JAI, memory leaks and jpeg2000, we have since built our own image library which includes a high speed JPEG2000 decoder and does not use JAI.
And if you work for Oracle, can you tell me where to send the patch?
In the end we gave up with trying to patch ImageIO and JAI and wrote our own ImageIO replacement from scratch. Lots of other developers seemed to have the problems so we made this commercially available as the JDeli Image library. You can find out more on the JDeli page.
Why use JDeli?
JDeli offers a range of advantages over ImageIO and alternatives, including:
- prevents heap related JVM crashes
- implements unsupported image formats
- reduce output file size
- improve read/write performance
- supports threading
- superior image scaling algorithms
Are you a Developer working with PDF files?
Our developers guide contains a large number of technical posts to help you understand the PDF file Format.
Do you need to solve any of these problems?
|Display PDF documents in a Web app|
|Use PDF Forms in a web browser|
|Convert PDF Documents to an image|
|Work with PDF Documents in Java|
19 Replies to “Java JAI image-io jpeg2000 Memory Leak fix”
You could try submitting a bug + patch to: http://java.net/jira/browse/JAI_IMAGEIO_CORE
Cheers Sean, I’ll give it a go.
It still has problems, I think in our case because our JP2s have a tile size equal to the image size and it must try to read in the entire tile even you set a small source region, and quickly runs out of (gigs of heap) memory.
java.lang.OutOfMemoryError: Java heap space
at jj2000.j2k.image.DataBlkInt.(Unknown Source)
at jj2000.j2k.wavelet.synthesis.InvWTFull.getInternCompData(Unknown Source)
at jj2000.j2k.image.ImgDataConverter.getData(Unknown Source)
at jj2000.j2k.image.ImgDataConverter.getInternCompData(Unknown Source)
at jj2000.j2k.image.invcomptransf.InvCompTransf.invRCT(Unknown Source)
at jj2000.j2k.image.invcomptransf.InvCompTransf.getInternCompData(Unknown Source)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KReadState.readSubsampledRaster(Unknown Source)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KReadState.readBufferedImage(Unknown Source)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReader.read(Unknown Source)
If the image is huge it will not fix that – it just frees the memory used afterwards.
What is the license for this jar? I can’t find any information.
Also, does the original jai-imageio’s license let you distribute a modified copy?
Best link we could find is http://kenai.com/projects/volumeviewer/sources/source-code-repository/content/lib/jai-imageio/LICENSE-codecLibJIIO.txt
I have emailed Oracle (we sent them the code fix) and spoke to the persion in charge at Javaone but still waiting for a response.
Just posted a message in the “What’s happening with JAI”-thread, before I saw this post.
It seems there are several parties interested in the same thing. As I stated in my previous post, I have working code that could be used as a starting point for a replacement. If someone would join in on the effort, that would be nice too. But right now, my main concern is, can (modified portions of) the jj2000 or JAI ImageIO be redistributed under a BSD license? Don’t want to make it a wasted effort.
It would really help if Oracle would make clear what they are up to (or if they have just abandoned it all).
For what it’s worth, I posted a follow-up in the JAI ImageIO forum on java.net too, but the “Is JAI maintained?” thread has been unanswered since June 14th…
I went and asked them at Javaone. I’ll try emailing again?
Yes, please do. Thanks. I emailed admins at jai.java.net last week, but I’m not really holding my breath…
Hi, do we have a happy end for this story?
I face the same issue and I do need to fix it, because I have a soft which need the read thousands of images.
Not really. We have patched the code to fix the specific issues we had.
There are several companies who might or do have 3rd party libraries. If you are looking for a commercial solution for JPEG and JPEG2000, I would recommend speaking to Accusoft – I visited them last week and they know their JPEGs very well.
I have to read various type of images. Recently I had to read thousands of png/tif and the memory leak occurred.
For png I can use imageio instead of JAI, but not for the tiff :@
I hoped it would have been fixed since 🙁
I believe the memory leak was JPEG 2000-specific?
FWIW I’ve created a BSD-licensed TIFF plugin that can be used with ImageIO directly, no need for JAI. Supports most baseline/common TIFFs.
PS: Haven’t heard anything form Oracle on JAI despite quite a few attempts/approaches, so I’ve pretty much given up.
It doesn’t appear to be jpeg specific 🙁
I never use jpeg because I work on image processing (therefore the jpeg compression screws everything).
Thank you very much for this link (didn’t know anything about it), it seems really easy to install/use!
I am gonna try it NOW!
Thanks for the link. I will pester Oracle again when I am at JavaOne.
I am facing memory leak issue on decompression of Jpeg2000 images using Jai Image IO library.
Can anyone please suggest fix for that issue? or anyone have the jai-imageio.jar file with the fixes?
The edited code is on our blog at https://blog.idrsolutions.com/2011/04/jai-memory-leak-source-changes/
You could also use our JDeli image library which is does not have these issues (and fixes lots of other bugs in JAI).