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