Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4707037

Components drawing animated images leak memory.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P4 P4
    • None
    • 1.4.0
    • client-libs
    • x86
    • windows_2000

      Name: jk109818 Date: 06/24/2002


      FULL PRODUCT VERSION :
      java version "1.4.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-
      b92)
      Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

      FULL OPERATING SYSTEM VERSION :
      Microsoft Windows 2000 [Version
      5.00.2195]

      A DESCRIPTION OF THE PROBLEM :
      This bug is somewhat related to bug 4215118. Component.imageUpdate() is
      called continuously by the Image fetcher thread until it returns false.
      Currently, Component.imageUpdate will *never* return false for
      animated images, even after removeNotify() has been called. This causes
      both unnecessary calls to methods that do nothing and more importantly a
      potentially huge leak, since a reference to the component has to be
      kept.

      Component.imageUpdate() needs to return false if it has no
      peer or if it is not visible.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Run the attached test case giving it an animated gif as the 1st argument
      (or simply put an animated gif named "image.gif" in the working
      directory). Make sure to give the JVM at least 40MB of memory.
      2. Press
      "Add Image". When the Image appears, press "Remove Image". Repeat until
      an OutOfMemoryError is thrown.
      3. Uncomment the imageUpdate() method
      in the test case.
      4. Recompile the test and rerun it. OutOfMemoryError
      will now not be thrown.

      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.*;
      import java.awt.event.*;

      public class ImageLeakTest{

      private static Frame frame;
      private static Button addButton, removeButton;
      private static Image image;

      private static Component leakingCanvas;

      public static void main(String [] args){
      frame = new Frame("Image Memory Leak test");
      frame.setLayout(new FlowLayout());

      image =
        Toolkit.getDefaultToolkit().getImage(args.length == 0 ? "image.gif" : args[0]);

      addButton = new Button("Add image");
      removeButton = new Button("Remove image");

      ButtonListener listener = new ButtonListener();

      removeButton.setEnabled(false);
      addButton.addActionListener(listener);
      removeButton.addActionListener(listener);

      frame.add(addButton);
      frame.add(removeButton);

      frame.setBounds(50,50,300,300);

      frame.addWindowListener(new AppKiller());

      frame.setVisible(true);
      }


      private static class ButtonListener implements ActionListener{

      public void actionPerformed(ActionEvent evt){
      if (evt.getSource() == addButton){
      addButton.setEnabled(false);
      removeButton.setEnabled(true);

      leakingCanvas = new LeakingCanvas(ImageLeakTest.image);
      frame.add(leakingCanvas);
      frame.doLayout();
      }
      else if (evt.getSource() == removeButton){
      addButton.setEnabled(true);
      removeButton.setEnabled(false);

      frame.remove(leakingCanvas);
      leakingCanvas = null;
      }
      }

      }

      private static class LeakingCanvas extends Canvas{

      // To make the memory leak more visible
      private byte [] byteArr = new byte[1024*1024*20];

      private Image image;

      public LeakingCanvas(Image image){
      this.image = image;
      }
      public void paint(Graphics g){
      g.drawImage(image,0,0,this);
      }

      public Dimension getPreferredSize(){
      return new Dimension(50,50);
      }

      // public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
      // if (getPeer() == null)
      // return false;
      // else
      // return super.imageUpdate(img,infoflags,x,y,w,h);
      // }

      }

      private static class AppKiller extends WindowAdapter{

      public void windowClosing(WindowEvent evt){
      System.exit(0);
      }

      }


      }
      ---------- END SOURCE ----------

      CUSTOMER WORKAROUND :
      Override Component.imageUpdate(Image, int, int, int, int, int) to
      return false if peer is null.
      (Review ID: 146760)
      ======================================================================

            Unassigned Unassigned
            jkimsunw Jeffrey Kim (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: