title: Possible memory leak when caching BufferedImage
body: <p>We have an application which serve images, to speed up the response time, we cache the <code>BufferedImage</code> directly in memory.</p>
  
  <pre><code>class Provider {
      @Override
      public IData render(String... layers,String coordinate) {
          int rwidth = 256 , rheight = 256 ;
  
          ArrayList&lt;BufferedImage&gt; result = new ArrayList&lt;BufferedImage&gt;();
  
          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&lt;BufferedImage&gt; 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;
      }
  }
  </code></pre>
  
  <p>usage:</p>
  
  <pre><code>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();
  
      }
  }
  </code></pre>
  
  <p>Note:the <code>provider</code> filed is a single instance.</p>
  
  <p>However it seems that there is a possible memory leak because I will get <code>Out Of Memory</code> exception when the application keep running for about 2 minutes.</p>
  
  <p>Then I use <code>visualvm</code> to check the memory usage:</p>
  
  <p><img src="https://i.stack.imgur.com/Y07Gz.png" alt="enter image description here"></p>
  
  <p>Even I <code>Perform GC</code> manually, the memory can not be released.</p>
  
  <p>And Though there are only 300+ <code>BufferedImage</code> cached, and <code>20M+</code> memory are used, <code>1.3G+</code> memory are retained. In fact, through "firebug" I can make sure that a generate image is less than <code>1Kb</code>. So I think the memory usage is not healthy.</p>
  
  <p>Once I do not use the cache (comment the following line):</p>
  
  <pre><code>//cacher.put(lkey, imageData);
  </code></pre>
  
  <p>The memory usage looks good:</p>
  
  <p><img src="https://i.stack.imgur.com/sCLSZ.png" alt="enter image description here"></p>
  
  <p>So it seem that the cached <code>BufferedImage</code> cause the memory leak.  </p>
  
  <p>Then I tried to transform the <code>BufferedImage</code> to <code>byte[]</code> and cache the <code>byte[]</code> instead of the object itself. And the memory usage is still normal. However I found the <code>Serialization</code> and <code>Deserialization</code> for the <code>BufferedImage</code> will cost too much time.</p>
  
  <p>So I wonder if you guys have any experience of image caching?</p>
  
  <hr>
  
  <p>update:</p>
  
  <p>Since there are so many people said that there is no memory leak but my cacher use too many memory, I am not sure but I have tried to cache <code>byte[]</code> instead of <code>BufferedImage</code> directly, and the memory use looks good. And I can not imagine 322 image will take up 1.5G+ memory,event as @BrettOkken said, the total size should be <code>(256 * 256 * 4byte) * 322 / 1024 / 1024 = 80M</code>, far less than 1Gb.</p>
  
  <p>And just now,I change to cache the <code>byte</code> and monitor the memory again, codes change like this:</p>
  
  <pre><code>BufferedImage ig = generateImage(layer,coordinate rwidth, rheight);
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  ImageIO.write(ig, "png", bos);
  imageData = bos.toByteArray();
  tileCacher.put(lkey, imageData);
  </code></pre>
  
  <p>And the memory usage:</p>
  
  <p><img src="https://i.stack.imgur.com/9VbFw.png" alt="enter image description here"></p>
  
  <p>Same codes, same operation.</p>