JCombobox是否会出现内存泄漏问题,即使完全没有引用它?
JCombobox是否会出现内存泄漏问题,即使完全没有引用它?
也许你们中的一些人可以帮我解决一个非常奇怪的问题,涉及到java和JComboboxes。我花了几个小时来追踪问题,但是我找不到解决方案。我不想在这里粘贴一个庞大的代码,但是这个简单的循环演示了它:
JComboBox cb; for(int i=0;i<1000;i++) { cb=new JComboBox(); }
我可以在任何地方运行这段代码,那1000个ComboBoxes从未被GCed,我不明白,为什么???
admin 更改状态以发布 2023年5月21日
我使用NBTestCase#assertGC
方法尝试了一个简单的测试用例。该方法的好处是,它会在出现内存泄漏时打印对象的强引用。它还通过填充堆内存以强制启动GC来触发GC。
我使用了一个非常简单的测试用例
public class ComboBoxMemoryLeak { public static void main( String[] args ) { EventQueue.invokeLater( new Runnable() { @Override public void run() { List> references = new ArrayList >( ); JComboBox comboBox; for (int i = 0; i < 1000; i++ ){ comboBox = new JComboBox( ); references.add( new WeakReference ( comboBox ) ); } comboBox = null; for ( int i = 0, referencesSize = references.size(); i < referencesSize; i++ ) { System.out.println( "i = " + i ); WeakReference weakReference = references.get( i ); NbTestCase.assertGC( "Combobox", weakReference ); } System.out.println("No memory leak found"); } } ); } }
在我运行JDK1.6的Mac上,产生以下跟踪结果
i = 0 Exception in thread "AWT-EventQueue-0" junit.framework.AssertionFailedError: Combobox: private static sun.awt.AppContext sun.awt.AppContext.mainAppContext-> sun.awt.AppContext@30f7f540-table-> java.util.HashMap@c324b85-table-> [Ljava.util.HashMap$Entry;@770fba26-[8]-> java.util.HashMap$Entry@63adf08f-value-> java.beans.PropertyChangeSupport@4f1b8540-children-> java.util.Hashtable@2305454a-table-> [Ljava.util.Hashtable$Entry;@4a9a4ba3-[0]-> java.util.Hashtable$Entry@6aed0f19-value-> java.beans.PropertyChangeSupport@23597cac-listeners-> sun.awt.EventListenerAggregate@2f39c244-listenerList-> [Ljava.beans.PropertyChangeListener;@2e2e06bd-[0]-> javax.swing.JViewport$1@2a72cf60-this$0-> javax.swing.JViewport@2b9c1dc4-parent-> javax.swing.JScrollPane@b99f7c6-parent-> com.apple.laf.AquaComboBoxPopup@6699166f-comboBox-> javax.swing.JComboBox@3bc634b9 at junit.framework.Assert.fail(Assert.java:50) at org.netbeans.junit.NbTestCase$4.run(NbTestCase.java:1351) at org.netbeans.junit.internal.NbModuleLogHandler.whileIgnoringOOME(NbModuleLogHandler.java:143) at org.netbeans.junit.NbTestCase.assertGC(NbTestCase.java:1309) at org.netbeans.junit.NbTestCase.assertGC(NbTestCase.java:1285) at ComboBoxMemoryLeak$1.run(ComboBoxMemoryLeak.java:32) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:677) at java.awt.EventQueue.access$000(EventQueue.java:85) at java.awt.EventQueue$1.run(EventQueue.java:638) at java.awt.EventQueue$1.run(EventQueue.java:636) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87) at java.awt.EventQueue.dispatchEvent(EventQueue.java:647) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
所以,是的,在我的机器上,我会得出JComboBox仍然通过 AppContext
中的引用存在于内存中的结论。在搜索这个问题时,我发现了这个stackoverflow的问题。我尝试将JConsole连接到一个带有while循环的主方法中并使用您的语句。不幸的是,在JConsole连接之前,我的主程序抛出了一个OutOfMemoryException
,因此我无法像trashgod在他的答案中那样生成漂亮的图片。
JComboBox会创建一个带有combobox监听器的DefaultListModel。因此,此类对象集群的垃圾回收被推迟了。然而,在第四次运行后,无论是垃圾回收还是JIT发现它不需要创建这些对象。
也许你的问题是显式调用System.gc()
而没有清理它?我能想象到这一点。
*如何追踪问题
我尝试了以下方法来排除组件。
private static class ReducedJComboBoxextends JComboBox { @Override public void setEditor(ComboBoxEditor anEditor) { } } public static void main( String[] args ) { System.out.println("; " + Runtime.getRuntime().freeMemory()); long t0 = System.currentTimeMillis(); ComboBoxModel model = new DefaultComboBoxModel(); ComboBoxEditor editor = new ComboBoxEditor() { public Component getEditorComponent() { throw new UnsupportedOperationException("Not supported yet."); } public void setItem(Object anObject) { } public Object getItem() { throw new UnsupportedOperationException("Not supported yet."); } public void selectAll() { } public void addActionListener(ActionListener l) { } public void removeActionListener(ActionListener l) { } }; JComboBox cb; for (int i = 0; i < 1000; i++) { cb = new JComboBox(); cb.setModel(model); cb.setEditable(false); cb.setEditor(editor); } long dt = t0 - System.currentTimeMillis(); System.out.println("dt=" + dt + " ms; " + Runtime.getRuntime().freeMemory()); System.gc(); System.out.println("finally " + Runtime.getRuntime().freeMemory()); }