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

Yet another java.awt.dnd.DropTarget causing JNI Global Reference leak?

XMLWordPrintable

    • 005
    • sparc
    • solaris_7


        This bug is similar to 4224888 and 4294016, but these bugs can not be reproduced on JDK1.2.2_05a, but the following example cause problems. See instructions in the code.


        import java.awt.*;
        import java.awt.dnd.*;
        import java.awt.event.*;
        import javax.swing.*;

        /**
         * Memory leak when using DropTarget. Tested on JDK 1.2.2 on
         * Windows NT (JDK1.2.2-003) and Solaris (JDK-1.2.2-05a).
         *
         * This simple application simulates the behaviour of our real
         * application. The user can work with a number of instances of
         * a certain window type, MainWindow. Main windows are opened
         * and closed in the the normal work flow, they are also drop
         * targets.
         *
         * Beacause of the bug, main windows are not garbage collected
         * when they are closed. This leads to the application running out
         * of memory after a while.
         *
         * Start the test application and open some (5) main windows from
         * the control window's File->Open. Make each main window a drop
         * target by selecting File->DropTarget in its menu. Run the garbage
         * collector from the control window's menu twice or more to get
         * the correct heap size. Close all main windows (from the window frame),
         * then open some more (5) main windows again and make each main window
         * a drop target. Run the garbage collector again
         * from the control window's menu (you probably have to
         * do this twice or more to get the correct heap size as the GC call is
         * asynchronous?). The heap size has now increased with a couple of
         * megabytes (each main window has a reference to a chunk of memory
         * to simulate the resources normaly held by the window's menu items,
         * action listeners, components, etc) and there are no output from
         * the MainWindow's finalizers.
         *
         * If the same procedure is repeated but the windows are not
         * made into drop targets, they are garbage collected (heap
         * doesn't increase, the finalizers are run).
         *
         * If you use OptimizeIt to look at allocated instances, you see
         * that MainWindows that were drop targets but have been closed are
         * still referenced by a JNI global reference.
         *
         * 2000-05-30 Jonas Ekström, ###@###.###
         */
        public class MiniGnip3 extends JFrame implements ActionListener {
          private JLabel memLabel_;

          public MiniGnip3() {
            super( "Control Window" );

            JMenuBar mb = new JMenuBar();
            setJMenuBar( mb );
            JMenu menu = new JMenu("File");
            mb.add( menu );
            JMenuItem item = new JMenuItem( "Open" );
            item.addActionListener( this );
            menu.add( item );
            item = new JMenuItem( "Run GC" );
            item.addActionListener( this );
            menu.add( item );
            item = new JMenuItem( "Exit" );
            item.addActionListener( this );
            menu.add( item );

            memLabel_ = new JLabel( "Heap: " + (Runtime.getRuntime().totalMemory() -
                                    Runtime.getRuntime().freeMemory()) );
            memLabel_.setHorizontalAlignment( SwingConstants.RIGHT );
            getContentPane().add( memLabel_ );
          }

          private void open() {
            MainWindow win = new MainWindow();
            win.pack();
            win.show();
          }

          private void runGc() {
            System.gc();
            memLabel_.setText( "Heap: " + (Runtime.getRuntime().totalMemory() -
                                           Runtime.getRuntime().freeMemory()) );
          }

          private void exit() {
            System.exit(0);
          }

          public void actionPerformed( ActionEvent e ) {
            if( e.getActionCommand().equals( "Open" ) )
              open();
            else if( e.getActionCommand().equals( "Run GC" ) )
              runGc();
            else if( e.getActionCommand().equals( "Exit" ) )
              exit();
          }

          public Dimension getPreferredSize() {
            return new Dimension( 180, 100 );
          }

          public static void main( String[] argv ) {
            MiniGnip3 win = new MiniGnip3();
            win.pack();
            win.show();
          }
        }

        class MainWindow extends JFrame {
          private DndManager dm_;
          private Meg meg_;
          public MainWindow() {
            setTitle( "Main " + getName() );

            JMenuBar mb = new JMenuBar();
            setJMenuBar( mb );
            JMenu menu = new JMenu();
            menu.setText( "File" );
            mb.add( menu );
                           
            JMenuItem mi = new JMenuItem( "DropTarget" );
            mi.addActionListener( new ActionListener() {
              public void actionPerformed( ActionEvent e ) {
                dm_ = new DndManager( MainWindow.this );
                setTitle( "DT " + getTitle() );
              }
            } );
            menu.add( mi );

            addWindowListener( new CloseCommand() );
            meg_ = new Meg();
          }

          public Dimension getPreferredSize() {
            return new Dimension( 200, 60 );
          }

          private void close() {
            System.out.println( "Disposing " + getName() );
            if( dm_ != null ) {
              dm_.clear(); // to try to stop being a drop target
              dm_ = null; // to get the DndManager GC'd
            }
            dispose();
          }

          protected void finalize() throws Throwable {
            super.finalize();
            System.out.println( getName() + " finalized." );
          }

          private class DndManager implements DropTargetListener {
            private DropTarget dt_;
            DndManager( Component comp ) {
              dt_ = new DropTarget( comp, DnDConstants.ACTION_COPY_OR_MOVE, this );
            }

            /**
             * Perform any action required to clear the window from being
             * a drop target and the DndManager from being a drop target
             * listener. Don't know if these have any effect, is there
             * anything else that can be done?
             */
            void clear() {
              dt_.removeDropTargetListener( this );
              dt_.setComponent( null );
            }

            protected void finalize() throws Throwable {
              super.finalize();
              System.out.println( "DndManager finalized." );
            }

            public synchronized void drop( DropTargetDropEvent dtde ) {}
            public void dragEnter( DropTargetDragEvent dtde ) {}
            public void dragExit( DropTargetEvent dropTargetEvent ) {}
            public void dragOver( DropTargetDragEvent dtde ) {}
            public void dropActionChanged( DropTargetDragEvent dtde ) {}
          }

          private class CloseCommand extends WindowAdapter {
            public void windowClosing( WindowEvent e ) {
              close();
            }
          }

          private class Meg {
            int[][] memory_ = new int[512][512];
          }
        }

        jonas.edberg@sweden 2000-06-05

              myangsunw Mingyao Yang (Inactive)
              duke J. Duke
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: