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

Unbounded memory leak in Windows XP JRE for Applets and applications that open JFrame's

    XMLWordPrintable

Details

    • b03
    • x86
    • solaris_10
    • Verified

    Backports

      Description

        FULL PRODUCT VERSION :
        1.5.0_08

        ADDITIONAL OS VERSION INFORMATION :
        Windows XP

        A DESCRIPTION OF THE PROBLEM :
        The test program does demonstrate a highly reproducible memory leak problem that is very serious (at least for the JVM on Windows XP ).

        The small test case allows you to create a frame and add tabbed components, each of which take 4MB of memory. It has buttons that force GC, and shows memory. Run the program and add tabs until you are close to the max memory for the JVM.

        Close the tabbed frame. It is set to dispose, and the reference to the tabbed frame is removed in a window listener.

        The "Update Memory Info" button reveals memory is not reclaimed. Hit "New Data" again, and try to add tabs to again reach the max memory. This time you get "OutOfMemoryError". Basically, the memory allocated by the tabbed frame never goes away until the application is stopped. This behavior occurs on Windows XP.

        On Solaris the behavior is as expected. One can add "New Data" until
        "OutOfMemoryError", close the tabbed frame, and then do a whole new
        series of "New Data", indefinitely.

        When the test case is run as an applet, the same behavior occurs with
        respect to the tabbed frame, but the memory leaking problem is even
        worse. Now, even the memory allocated by the applet never gets
        reclaimed. If the applet is navigated to, and the memory examined, and
        then the back / front browser buttons are used to destroy the applet
        and create a new one, the memory reveals the first applets memory is
        still allocated. If the tabbed frame is opened from the applet, and then
        the brower back button is used to destroy the applet, the memory for the
        applet and all of the memory allocated by the tabbed frame is never
        freed (until the browser is killed). This is despite the fact that on
        destroy the test applet asks the tabbed from to remove all components.

        Again, this behavior is seen on Windows XP (SP2) with 1.5.0_08 but not
        on Solaris 10 (same version of JDK).


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        As per description

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        No memory leak in the Applets / applications that open JFrame's
        ACTUAL -
        Memory leak.

        ---------- BEGIN SOURCE ----------
        Test case TestApplet.java:

        import javax.swing.*;
        import java.awt.*;
        import java.awt.event.*;
        import java.lang.reflect.InvocationTargetException;

        public class TestApplet extends JApplet implements WindowListener {

            private static int frameCounter;
            private JLabel memoryLabel;
            private TabbedFrame atf;
            private byte[] spaceHog = new byte[1024 * 1024 * 4];
            private int classFrameCounter;

            public void destroy() {
                if (atf != null) {
                    atf.removeAll();
                    atf.dispose();
                    atf = null;
                }
                super.destroy();
            }

            public void init() {
                memoryLabel = new JLabel("Hit the update button");
                JButton updateMemory = new JButton("Update Memory Info");
                updateMemory.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        // Stimulate the gc system to get new memory -- this must force gc on old objects.
                        int megs = 7;
                        byte[][] bytes = new byte[2000][];
                        int i = 0;
                        while (true) {
                            try {
                                bytes[i % 2000] = new byte[megs * 1024 * 1024];
                                i++;
                            } catch (OutOfMemoryError e1) {
                                bytes = null;
                                break;
                            }
                        }
                        bytes = null;
                        final Runtime rt = Runtime.getRuntime();
                        rt.gc();
                        rt.gc();
                        final long maxMem = rt.maxMemory();
                        final long totalMem = rt.totalMemory();
                        final long freeMem = rt.freeMemory();
                        final double bpmb = 1024 * 1024;
                        memoryLabel.setText(String.format("Max=%1.2f MB Total=%1.2f MB Free=%1.2f MB Used=%1.2f MB", maxMem / bpmb,
        totalMem / bpmb, freeMem / bpmb, (totalMem - freeMem) / bpmb));
                    }
                });

                final JButton frameButton = new JButton("New Data");
                frameButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        if (atf == null) {
                            atf = new TabbedFrame((++frameCounter) + " : " +
        (++classFrameCounter));
                           
        atf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                            atf.addWindowListener(TestApplet.this);
                            atf.validate();
                            atf.setVisible(true);
                        } else {
                            atf.addData();
                            atf.setVisible(true);
                        }
                    }
                });

                final JButton clearButton = new JButton("Clear All Tabs");
                clearButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        if (atf != null) {
                            atf.clearData();
                            atf.setVisible(true);
                        }
                    }
                });

                final JPanel buttonPanel = new JPanel();
                buttonPanel.add(updateMemory);
                buttonPanel.add(frameButton);
                buttonPanel.add(clearButton);

                add(memoryLabel, BorderLayout.NORTH);
                add(buttonPanel, BorderLayout.SOUTH);
            }

            public void windowActivated(final WindowEvent e) {
            }

            public void windowClosed(final WindowEvent e) {
                final Object src = e.getSource();
                if (src == atf) {
                    System.out.println("Frame closed. Reference to frame nulled.");
                    atf = null;
                }
            }

            public void windowClosing(final WindowEvent e) { }
            public void windowDeactivated(final WindowEvent e) { }
            public void windowDeiconified(final WindowEvent e) { }
            public void windowIconified(final WindowEvent e) { }
            public void windowOpened(final WindowEvent e) { }

            public static class TabbedFrame extends JFrame {
                private int counter = 0;
                private JTabbedPane tabbedPane;
                private byte[] bigData = new byte[1024 * 1024 * 4];
                public TabbedFrame(final String title) throws HeadlessException{
                    setTitle("Test Frame " + title);
                    setSize(500, 400);
                    tabbedPane = new JTabbedPane();
                    add(tabbedPane);
                }

                public void addData() {
                    tabbedPane.addTab(Integer.toString(counter++), new
        DataPanel());
                }

                public void clearData() {
                    final Component[] c = tabbedPane.getComponents();
                    for (int i = 0; i < c.length; i++) {
                        tabbedPane.remove(c[i]);
                    }
                }

                private static class DataPanel extends JPanel {

                    private byte[] bigData = new byte[1024 * 1024 * 4];
                    public DataPanel() {
                        add(new JButton("Proxy for data showing panel"));
                    }
                }
            }

            public static void main(final String[] args) throws
        InvocationTargetException, InterruptedException {
                final TestApplet applet = new TestApplet();
                EventQueue.invokeAndWait(new Runnable() {
                    public void run() {
                        final JFrame frame = new JFrame("Myriad Test");

                        applet.init();
                        applet.start();

                        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        frame.add(applet, BorderLayout.CENTER);
                        frame.setSize(500, 200);
                        frame.validate();
                        frame.setVisible(true);
                    }
                });
            }
        }
        ---------- END SOURCE ----------

        REPRODUCIBILITY :
        This bug can be reproduced always.

        Attachments

          Issue Links

            Activity

              People

                bchristi Brent Christian
                ndcosta Nelson Dcosta (Inactive)
                Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: