4

We have been using BufferedImage objects in our application to render the PNG images, unfortunately after performing certain operations like rotating and resizing the images (in turn these operations create and return the new BufferedImage object with updated length and width) the java heap size goes high and high to lead the OutofMemory error.

Even after closing down the current panel GC is not reclaiming the memory consumed by these BufferedImage object, I have read lot of threads mentioning that older versions of JDK itself (prior to 1.5) having memory leak in BufferedImage, but didn’t find any work around or fix for this. Even in the later versions of JDK for example at the movement we are using jdk1.6.0_26 and still able to see this issue.

It will be great if someone can suggest some tips to stop the memory leak with BufferedImage object or any other alternative implementations for that object?

vulkanino
  • 9,074
  • 7
  • 44
  • 71
Ramesh
  • 49
  • 1
  • 2
  • 8
    Maybe a code snipped that one could use to reproduce the problem would help. – Simon Feb 28 '12 at 15:30
  • 2
    also the jvm options you run with could help – aviad Feb 28 '12 at 15:36
  • 1
    It's unlikely `BufferedImage` itself is the root cause of the problem. Run your program with a tool like VisualVM to discover where the real problem is (http://visualvm.java.net/) – Joni Feb 28 '12 at 15:38
  • @user1238131: you should make sure to *flush()* the *BufferedImage*. Setting the reference to *null* (or reusing the ref for another image) is not enough: you should call *flush()* first too. The answer here is wrong btw: http://stackoverflow.com/questions/7641208/when-is-it-safe-or-mandatory-to-use-image-flush It says that you are never forced to *flush*. But this is simply not true: there are current JVMs (*e.g.* on older OS X versions -- still in use today by a lot of people), where not flush()ing creates leak. I'm not saying flush() shall solve all your problems, but it may help... – TacticalCoder Feb 28 '12 at 15:39
  • Do you sever all pointers to old images and use `System.gc();`? – Mark Jeronimus Feb 28 '12 at 15:40
  • 1
    @user1238131 where is the code? stop using invisible ink ;) – Adrian Feb 28 '12 at 15:59
  • private BufferedImage rotateImage(Connection.Orientation orientation, WeakReference image) { final boolean verticalOrientation = orientation == Connection.Orientation.ROTATE_90_DEG_ANTI_CLOCKWISE || orientation == Connection.Orientation.ROTATE_270_DEG_ANTI_CLOCKWISE; final int newWidth = verticalOrientation ? image.get().getHeight() : image.get().getWidth(); final int newHeight = verticalOrientation ? image.get().getWidth() : image.get().getHeight(); – Ramesh Feb 28 '12 at 16:06
  • BufferedImage retImage = new BufferedImage(newWidth, newHeight, image.get().getType()); final int numQuadrants = orientation == Connection.Orientation.NO_ROTATION ? 0 : orientation == Connection.Orientation.ROTATE_90_DEG_ANTI_CLOCKWISE ? 1 : orientation == Connection.Orientation.ROTATE_180_DEG_ANTI_CLOCKWISE ? 2 : 3; final int width = image.get().getWidth(); – Ramesh Feb 28 '12 at 16:07
  • final int height = image.get().getHeight(); AffineTransform xform = new AffineTransform(); xform.translate(0.5*newWidth, 0.5*newHeight); xform.rotate(-numQuadrants * (Math.PI / 2.0)); xform.translate(-0.5*width, -0.5*height); Graphics2D g = retImage.createGraphics(); g.drawImage(image.get(), xform, null); g.dispose(); return retImage; } – Ramesh Feb 28 '12 at 16:07
  • 2) Aviad, I have already set the heap size to 1024MB using jvm memory options, but if the used java heap goes behind 1024MB ultimately we will get the outofmemoryerror. 3) Joni, Yes I have used jvisualvm tool provided by JDK to track the memory usage. Each time I rotate the image, that size for byte[] is getting increased by 14 - 15 MB. Also have seen lot of threads discussing about the memory leak in BufferedImage object, even Oracle accepted to fix it but not sure when they are going to do that. – Ramesh Feb 28 '12 at 16:08
  • 4) TacticalCOder, yes I have tried using flush method but there is no difference. 5) Zoom-B, yes references to all pointers are removed. Tried using WeakReferences to these objects still I'm facing this problem. – Ramesh Feb 28 '12 at 16:08
  • I have seen more details about this issue in the below link, where Oracle accepted to fix it but not sure when they are going to do that. Can someone please provide me the details, if they have face this problem and able to fix it. http://bugs.sun.com/view_bug.do?bug_id=6716560 – Ramesh Feb 29 '12 at 11:42
  • @Ramesh the OutOfMemoryException often occurs in BufferedImage because it's a class that usually allocates a lot of memory. But the leak (or "memory theft" in other owrkds) can be done somewhere else. – Adam Dyga Apr 12 '13 at 14:03

2 Answers2

2

You should try to just use an AffineTransform with the Graphics2D method drawImage (or any other that take an AffineTransform object).

These AffineTransform objects are transformation matrices, they can keep all your image operations in one matrix and then apply that transformation matrix to the image at the cost of 1 transformation.

You can do any of four things with the transformation matrix:

  • translation
  • rotation
  • scale
  • shear

Also this way, you won't have to construct a new BufferedImage every time you apply a tranformation.

Falx
  • 144
  • 7
-3

We are having the same trouble here. We are using a lot of JChart instances and the memory is leaking easily.

All leaks occur in java.awt.image.BufferedImage.

The solution that we found is:

  • Remove the Object reference BufferedImage in your case. object.remove() or object = null
  • Call Garbage Collector System.gc(). That will realy free your memory.

But GC's use is a bit expensive.