Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
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.
|