ryanqq / macwidgets

Automatically exported from code.google.com/p/macwidgets
0 stars 0 forks source link

Memory leak caused by SkinnableScrollBarUI #120

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Run the following problem using your favorite profiler:
[code]
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import com.explodingpixels.macwidgets.IAppWidgetFactory;

public class MemoryLeakTestApplication
{
   private static final JPanel content = new JPanel(new BorderLayout());

   public static void main(String[] args)
   {
      JComponent view = MemoryLeakTestApplication.createView();
      MemoryLeakTestApplication.content.add(view, BorderLayout.CENTER);
      MemoryLeakTestApplication.content.add(new JButton(new
ToggleViewAction(view)), BorderLayout.SOUTH);

      JFrame frame = new JFrame("Memory leak test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(MemoryLeakTestApplication.content);
      frame.setSize(300, 300);
      frame.setVisible(true);
   }

   private static JComponent createView()
   {
      JTextArea txt = new JTextArea(

"text\ntext\ntext\ntext\ntext\ntext\ntext\ntext\ntext\ntext\ntext\ntext\ntext\nt
ext\ntext\ntext\ntext\ntext\ntext\n");
      txt.setEditable(false);
      txt.setEnabled(false);
      JScrollPane scroll = new JScrollPane(txt);
      IAppWidgetFactory.makeIAppScrollPane(scroll);
      return scroll;
   }

   private static class ToggleViewAction extends AbstractAction
   {
      private JComponent oldView;

      private ToggleViewAction(JComponent oldView)
      {
         super("Remove scrollpane");
         this.oldView = oldView;
      }

      public void actionPerformed(ActionEvent e)
      {
         MemoryLeakTestApplication.content.remove(this.oldView);
         this.oldView = null;
         MemoryLeakTestApplication.content.add(new JLabel("Scroll pane
should now be garbadge collected."),
               BorderLayout.CENTER);
         MemoryLeakTestApplication.content.validate();
         System.gc();
         super.setEnabled(false);
      }
   }
}
[/code]

The JTextArea and the JScrollPane should be garbage collected, but due to
the WindowListener added by com.explodingpixels.widgets.WindowUtils this
does not happen. This listener should be uninstalled when the JScrollPane
is removed from the screen.

I am using mac_widgets-0.9.5 on Linux with Java6u10.

Original issue reported on code.google.com by jethroborsje on 14 Aug 2009 at 8:50

GoogleCodeExporter commented 9 years ago

Original comment by kenneth....@gmail.com on 16 Aug 2009 at 7:24

GoogleCodeExporter commented 9 years ago
I believe I've fixed this. Would you mind verifying? You'll find the latest Mac 
Widgets for Java build here:

http://www.macwidgetsforjava.com/downloads/latest/mac_widgets.jar

Thanks again for finding and reporting this.

Original comment by kenneth....@gmail.com on 19 Aug 2009 at 11:04

GoogleCodeExporter commented 9 years ago
Thank you for spending time on this issue.

The memory leak is still there with the new version, however the live reference 
to
the JScrollPane and its components is no longer being held by the 
WindowListener. The
path to the GC root is as follows:
[path]
javax.swing.JScrollPane
- parent of com.explodingpixels.widgets.ImageBasedJComponent
-- SCROLL_PANE_CORNER of com.explodingpixels.macwidgets.IAppWidgetFactory
--- [32] of java.lang.Object[80]
---- elementData of java.util.Vector
----- classes of sun.misc.Launcher$AppClassLoader [Held by JVM]
[/path]

Does this help?

Original comment by jethroborsje on 19 Aug 2009 at 11:59

GoogleCodeExporter commented 9 years ago
That does help. I had a static JComponent in the scrollpane's corner, which was 
preventing it from being garbage 
collected. Can you grab the jar and try it again.

Thanks for testing this!

Original comment by kenneth....@gmail.com on 19 Aug 2009 at 12:39

GoogleCodeExporter commented 9 years ago
I did another test, the problem with the static JComponent is no longer there,
however the memory leak is not yet solved. This is the path to the GC root now:
[path]
javax.swing.JScrollPane
- this$0 of javax.swing.JScrollPane$ScrollBar
-- val$component of com.explodingpixels.widgets.WindowUtils$3
--- b of java.awt.AWTEventMulticaster
---- windowListener of javax.swing.JFrame
----- currentFocusCycleRoot of java.awt.KeyboardFocusManager [Class]
[/path]

Original comment by jethroborsje on 19 Aug 2009 at 1:43

GoogleCodeExporter commented 9 years ago
OK, I think I got it this time. I changed WindowUtils to use a WeakReference 
when it installs WindowListeners. 
Can you try this again? Thanks again for the help.

Original comment by kenneth....@gmail.com on 19 Aug 2009 at 2:32

GoogleCodeExporter commented 9 years ago
Yes, it is fixed now!

Original comment by jethroborsje on 20 Aug 2009 at 6:59

GoogleCodeExporter commented 9 years ago
I'm not sure whether my code is just slightly different, but I still see a 
memory leak using r401 and very similar application code. Removing the call to 
WindowUtils.installJComponentRepainterOnWindowFocusChanged(scrollbar); in 
SkinnableScrollBarUI fixes the problem.

I can try to put together a minimal example if this would help.

Original comment by b.webs...@itisint.com on 25 May 2012 at 9:06