We have an application that serves images to speed up response time, we cache BufferedImage directly in memory.
class Provider { @Override public IData render(String... layers,String coordinate) { int rwidth = 256 , rheight = 256 ; ArrayList<BufferedImage> result = new ArrayList<BufferedImage>(); for (String layer : layers) { String lkey = layer + "-" + coordinate; BufferedImage imageData = cacher.get(lkey); if (imageData == null) { try { imageData = generateImage(layer, coordinate,rwidth, rheight, bbox); cacher.put(lkey, imageData); } catch (IOException e) { e.printStackTrace(); continue; } } if (imageData != null) { result.add(imageData); } } return new Data(rheight, rheight, width, result); } private BufferedImage generateImage(String layer, String coordinate,int rwidth, int rheight) throws IOException { BufferedImage image = new BufferedImage(rwidth, rheight, BufferedImage.TYPE_INT_ARGB); Graphics2D g = image.createGraphics(); g.setColor(Color.RED); g.drawString(layer+"-"+coordinate, new Random().nextInt(rwidth), new Random().nextInt(rheight)); g.dispose(); return image; } } class Data implements IData { public Data(int imageWidth, int imageHeight, int originalWidth, ArrayList<BufferedImage> images) { this.imageResult = new BufferedImage(this.imageWidth, this.imageHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D g = imageResult.createGraphics(); for (BufferedImage imgData : images) { g.drawImage(imgData, 0, 0, null); imgData = null; } imageResult.flush(); g.dispose(); images.clear(); } @Override public void save(OutputStream out, String format) throws IOException { ImageIO.write(this.imageResult, format, out); out.flush(); this.imageResult = null; } }
using:
class ImageServlet extends HttpServlet { void doGet(req,res){ IData data= provider.render(req.getParameter("layers").split(",")); OutputStream out=res.getOutputStream(); data.save(out,"png") out.flush(); } }
Note: a registered provider is one instance.
However, it seems that there is a possible memory leak, because I get an Out Of Memory exception when the application runs for about 2 minutes.
Then I use visualvm to check for memory usage:

Even I Perform GC manually, memory cannot be freed.
Although only 300 + BufferedImage used for caching and 20M+ memory is used, 1.3G+ memory is 1.3G+ . In fact, through "firebug" I can make sure that the generated image is less than 1Kb . Therefore, I think that using memory is not healthy.
As soon as I will not use the cache (comment the following line):
Memory usage looks good:

It seems that the cached BufferedImage is causing a memory leak.
Then I tried to convert BufferedImage to byte[] and cache byte[] instead of the object itself. And memory usage is still normal. However, I found that Serialization and Deserialization for BufferedImage would cost too much time.
So, I wonder if you have experience caching images?
update:
Since so many people say that there is no memory leak, but my cacher uses too much memory, I'm not sure, but I tried to cache byte[] instead of BufferedImage directly, and the memory usage looks good, And I can not imagine that image 322 will take 1.5G + memory, the event, as @BrettOkken said, the total size should be (256 * 256 * 4byte) * 322 / 1024 / 1024 = 80M , much smaller than 1Gb.
And only now I go to the byte cache and track the memory again, the codes change as follows:
BufferedImage ig = generateImage(layer,coordinate rwidth, rheight); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(ig, "png", bos); imageData = bos.toByteArray(); tileCacher.put(lkey, imageData);
And memory usage:

Same codes, same action.