5

This question is a result of the answers provided to me for my previous question.

I was asked to use Eclipse MAT to investigate what is eating up my heap. Below are my observations (Top Consumers):

class sun.awt.SunToolkit                                 333.7 MB
com.tennisearth.service.impl.CacheManagerServiceImpl     136 MB
org.apache.jasper.servlet.JspServlet                     91.5 MB

I have already fixed the issue with CacheManageServiceImpl, but require help with SunToolkit.

Below is the code that creates an Image object (which internally uses SunToolkit.imgCache)

Image img = new ImageIcon(imagePath).getImage();
int imageWidth = img.getWidth(null);
int imageHeight = img.getHeight(null);

Plz note that the Image object is only being created to get the width / height of the image which is required later in some logic.

Is there a way to disable SunToolkit image caching? Better yet, is there a way to clear this cache? Or is there a better way I can retrieve this information?

BTW for your reference, I am using the below command to run jboss (plz note the heap size arguments):

java -Dprogram.name=run.sh -server -Xms256m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m -verbose:gc -Xloggc:/data1/logs/jboss/GC.log -XX:+HeapDumpOnOutOfMemoryError -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE=false -Djava.net.preferIPv4Stack=true -Djava.library.path=/usr/local/java/jboss-4.2.2.GA/bin/native -Djava.endorsed.dirs=/usr/local/java/jboss-4.2.2.GA/lib/endorsed -classpath /usr/local/java/jboss-4.2.2.GA/bin/run.jar:/usr/local/java/jdk1.6.0_06/lib/tools.jar org.jboss.Main -c default -b <IP_ADDRESS> -Djboss.messaging.ServerPeerID=1

Sumit

Community
  • 1
  • 1
Sumit
  • 540
  • 9
  • 20
  • 1
    there are a *lot* of issues in Java related to images and image caching. The infamous *flush()* workaround around API defects spring to mind. Nullifying images is not always enough: sometimes you need to call *flush()* yourself and it simply makes no sense. If it's on a server, I'd just get that width/height info by running externally ImageMagick's *identify* command. It's a bit of a pain to run an external process but then loading an image just to get it's width/height on a server is quite heavyweight too. – SyntaxT3rr0r Mar 09 '11 at 14:35
  • another option... We were batch processing all our pictures and putting the widht/height info directly in the picture's filename: *mypic.jpg* becomes *mypic640x480.jpg*. Then we simply extracted the (w,h) from the filename... – SyntaxT3rr0r Mar 09 '11 at 14:36
  • if you want to Google on this issue, here's an interesting quote: *We have seen the flush issue on other platforms than OS X, so I think the "proper" fix needs to be put in by Sun, by implementing finalize on ToolkitImage to force a flush before GC reclaims the image. Has anyone reported this to Sun?* – SyntaxT3rr0r Mar 09 '11 at 14:38
  • I ship a Java app on hundreds of different Windows/OS X making heavy use of images and I can tell: there **are** definitely bugs left and right and we're seeing OutOfMemory errors that should never have happened had these APIs been correctly designed/implemented by Sun. – SyntaxT3rr0r Mar 09 '11 at 14:39
  • @SyntaxT3rr0r: Thanks for your reply. Unfortunately, using an external command is not an option and I would also like to make use of the internal cache mechanism to speed up the process. As per Jorn's comment, the cache expiry is handled by the JVM itself so I am not to worry about it. – Sumit Mar 09 '11 at 14:44

2 Answers2

3

The image cache seems to be implemented by a class named SoftCache, its documentation states the following:

A memory-sensitive implementation of the Map interface.

A SoftCache object uses java.lang.ref.SoftReference to implement a memory-sensitive hash map. If the garbage collector determines at a certain point in time that a value object in a SoftCache entry is no longer strongly reachable, then it may remove that entry in order to release the memory occupied by the value object. All SoftCache objects are guaranteed to be completely cleared before the virtual machine will throw an OutOfMemoryError.

So I would not worry about the memory taken by this cache since it will get cleared automatically when the memory is needed elsewhere.

Edit: After reading the comments by SyntaxT3rr0r, I think it could still be worthwhile to call flush on the Image. If this is part of a larget method you could also set image to null or refactor so it goes out of scope sooner.

Another possibility would be to try the ImageIO Api to retrieve the width and height. This should be possible by getting a ImageReader for the image type.

Community
  • 1
  • 1
Jörn Horstmann
  • 33,639
  • 11
  • 75
  • 118
  • 1
    Thanks alot for your clarification. Glad am not to worry about this anymore :) – Sumit Mar 09 '11 at 14:33
  • Just saw your edit, I still would like to use image caching to speed up the process of creating the image object. I believe flushing the image wont be able to use this cache. Right? – Sumit Mar 09 '11 at 15:40
  • 1
    @Sumit, I don't know exactly which caches are flushed by that call. If you repeatedly query the width and height for the same image path it might also make sense to implement a simple cache yourself, like a `Map`. That would avoid the need to recreate the image once the imgCache is cleared up by the gc. – Jörn Horstmann Mar 09 '11 at 16:33
  • I have the exact problem that the image cache is keeping very large images in memory for slightly too long. I try to load another large image and it gets out of memory as the GC doesnt seem to run in time. I.e we load 40 or 50 Mb images and convert them to smaller images. Forcing the GC via jconsole between each image load fixes it but during normal operation it sometimes gets out of memory. – Neil Wightman May 06 '11 at 13:56
1

Is it possible your Image object remains in scope for long periods of time? For example, if it's contained in the outer scope of a block of code that runs for long periods of time, it may not be properly garbage collected.

Sometimes (in rare cases), it's beneficial to explicitly set your Image object reference to null. This would be true in the case I mentioned above. See the following question for more info: Does assigning objects to null in Java impact garbage collection?

Community
  • 1
  • 1
Madison Caldwell
  • 862
  • 1
  • 7
  • 16