JPanels的Java内存泄漏问题

JPanels的Java内存泄漏问题,java,Java,Java内存泄漏 private boolean refreshResponseWindow(MessageObject message) { this.responsePanel.removeAll(); this.responsePanel.add(message.buildGUI()); this.responsePanel.validate(); message = null; return true; } 出现的问题是,当我收到越来越多的消息时,我的Java程序的

Java内存泄漏

private boolean refreshResponseWindow(MessageObject message) {
  this.responsePanel.removeAll();
  this.responsePanel.add(message.buildGUI());
  this.responsePanel.validate();
  message = null;
  return true;
}

出现的问题是,当我收到越来越多的消息时,我的Java程序的内存使用继续增长,最终导致它被锁定。我已经将内存泄漏隔离到上面的代码中,特别是add过程调用。我想removeAll会清除我面板上的内容,但它似乎仍在继续增长

注意:message.buildGUI()返回一个显示在responsePanel上的JPanel

后续行动:

BuildGUI代码就是这样显示的

public JPanel buildGUI() throws Exception {
    JPanel busPanel = new JPanel();
    busPanel.setLayout(new GridBagLayout());
    busPanel.setPreferredSize(new Dimension(Globals.panelW, Globals.panelH));
    busPanel.setMinimumSize(new Dimension(Globals.panelW, Globals.panelH));

    final JLabel headingLabel = new JLabel();
    headingLabel.setFont(new Font("", Font.PLAIN, 18));
    headingLabel.setText(this.name);
    final GridBagConstraints gridBagConstraints_heading = new GridBagConstraints();
    gridBagConstraints_heading.gridwidth = 2;
    gridBagConstraints_heading.gridy = 0;
    gridBagConstraints_heading.gridx = 0;
    busPanel.add(headingLabel, gridBagConstraints_heading);
    //Many more gui components marked as final
    return busPanel;

没有侦听器返回的面板仅用于显示目的

buildGUI方法是否向业务对象添加侦听器?这是内存泄漏的常见来源。调用
responsePanel.removeAll()
将删除组件,但组件仍可能注册为
responsePanel
或其他对象上的侦听器,导致它们保留在内存中。
buildGUI
方法是否将侦听器添加到业务对象中?这是内存泄漏的常见来源。调用
responsePanel.removeAll()
将删除组件,但这些组件仍可能在
responsePanel
或其他对象上注册为侦听器,导致它们保留在内存中。

以下是removeAll()内存泄漏问题的解决方案…
我称之为成分湮灭。

它效率不高,除非你真的需要,否则我不建议你使用它。
可以通过指定要查找的侦听器类型来加快速度。

注意:它将从面板中删除LayoutManager,因此您需要重新添加它

使用示例:


Utils.annihilateComponent(myJPanel,null,null); // This is slow if myJPanel has many components
myJpanel.setLayout(new FlowLayout());

Utils.annihilateComponent(myJPanel,new String[]{"Action","Mouse","PopupMenu"},new String[]{"java.awt.event.","javax.swing.event."});
myJPanel.setLayout(new MigLayout());
myJPanel.add(new JLabel("Once you start using MigLayout you'll never look back"),"wrap");

//In an JDialog:
private void formWindowClosing(java.awt.event.WindowEvent evt) {
    Utils.annihilateComponent(this);
}

代码如下:


import java.awt.*;
import java.lang.reflect.Method;
import java.util.EventListener;

public class Utils {
    private static String[] allPackages = { "java.awt.event.","javax.swing.event.","java.beans.","java.beans.beancontext."
            ,"java.awt.dnd.","javax.sql.","javax.naming.event.","javax.imageio.event.","javax.net.ssl.","javax.sound.midi."
            ,"javax.naming.ldap.","java.util.prefs.","javax.sound.sampled." };
    public static void removeListeners (Object o, String listenerName, String[] packages) {
        Class oc = o.getClass();
        try {
            Method getListenersMethod = oc.getMethod("get"+listenerName+"Listeners",(Class[])null);
            String[] p;
            if (packages == null) {
                p = allPackages;
            } else {
                p = packages;
            }

            // Find the listener Class
            Class listenerClass = null;
            int pIndex = 0;
            while (listenerClass == null && pIndex < p.length) {
                try {
                    listenerClass = Class.forName(p[pIndex]+listenerName+"Listener");
                } catch (Exception ex) {
                    /* Ignore */
                }
                pIndex++;
            }
            if (listenerClass == null) {
                return; // Couldn't find the class for this listener type
            }

            Method removeListenerMethod = oc.getMethod("remove"+listenerName+"Listener", new Class[] { listenerClass });
            if (getListenersMethod != null) {
                    //res1 = m.invoke(dto1,(Object[])null);

                Object els = getListenersMethod.invoke(o,(Object[])null);
                if (els instanceof EventListener[]) {
                    EventListener[] listeners = (EventListener[])els;
                    for (int i = 0; i < listeners.length; i++) {
                        removeListenerMethod.invoke(o, new Object[] { listeners[i] });
                    }
                }
            }
        } catch (Exception e) {
            // Ignore
        }
    }

    private static String[] allListeners = { "Action","Adjustment","Ancestor","AWTEvent","BeanContextMembership","BeanContextServiceRevoked"
            ,"BeanContextServices","Caret","CellEditor","Change","Component","ConnectionEvent","Container","ControllerEvent"
            ,"Document","DragGesture","DragSource","DragSourceMotion","DropTarget","Focus","HandshakeCompleted","HierarchyBounds"
            ,"Hierarchy","Hyperlink","IIOReadProgress","IIOReadUpdate","IIOReadWarning","IIOWriteProgress","IIOWriteWarning"
            ,"InputMethod","InternalFrame","Item","Key","Line","ListData","ListSelection","MenuDragMouse","MenuKey","Menu"
            ,"MetaEvent","MouseInput","Mouse","MouseMotion","MouseWheel","NamespaceChange","Naming","NodeChange","ObjectChange"
            ,"PopupMenu","PreferenceChange","PropertyChange","RowSet","SSLSessionBinding","TableColumnModel","TableModel"
            ,"Text","TreeExpansion","TreeModel","TreeSelection","TreeWillExpand","UndoableEdit","UnsolicitedNotification"
            ,"VetoableChange","WindowFocus","Window","WindowState" } ;

    public static void removeAllListeners(Component c, String[] listeners, String[] packages) {
        String[] l;
        if (listeners == null) {
            l = allListeners;
        } else {
            l = listeners;
        }
        for (int i = 0; i < l.length; i++) {
            removeListeners(c,l[i],packages);
        }
    }

    public static void annihilateComponent(Object o, String[] listeners, String[] packages) {
        if (o == null) {
            return;
        }
        if (o instanceof Container) {
            Component[] c = ((Container)o).getComponents();
            for (int i = 0; i < c.length; i++) {
                annihilateComponent(c[i],listeners,packages);
            }
            ((Container)o).setLayout(null);
            ((Container)o).setFocusTraversalPolicy(null);
            ((Container)o).removeAll();
        }
        if (o instanceof javax.swing.JScrollPane) {
            ((javax.swing.JScrollPane)o).setViewportView(null);
        }
        if (o instanceof Component) {
            removeAllListeners((Component)o,listeners,packages);
        }
        if (o instanceof Window) {
            ((Window)o).dispose();
        }
    }

    public static void annihilateComponent(Object o) {
        annihilateComponent(o,null,null);
    }
}

以下是removeAll()内存泄漏问题的解决方案…
我称之为成分湮灭。

它效率不高,除非你真的需要,否则我不建议你使用它。
可以通过指定要查找的侦听器类型来加快速度。

注意:它将从面板中删除LayoutManager,因此您需要重新添加它

使用示例:


Utils.annihilateComponent(myJPanel,null,null); // This is slow if myJPanel has many components
myJpanel.setLayout(new FlowLayout());

Utils.annihilateComponent(myJPanel,new String[]{"Action","Mouse","PopupMenu"},new String[]{"java.awt.event.","javax.swing.event."});
myJPanel.setLayout(new MigLayout());
myJPanel.add(new JLabel("Once you start using MigLayout you'll never look back"),"wrap");

//In an JDialog:
private void formWindowClosing(java.awt.event.WindowEvent evt) {
    Utils.annihilateComponent(this);
}

代码如下:


import java.awt.*;
import java.lang.reflect.Method;
import java.util.EventListener;

public class Utils {
    private static String[] allPackages = { "java.awt.event.","javax.swing.event.","java.beans.","java.beans.beancontext."
            ,"java.awt.dnd.","javax.sql.","javax.naming.event.","javax.imageio.event.","javax.net.ssl.","javax.sound.midi."
            ,"javax.naming.ldap.","java.util.prefs.","javax.sound.sampled." };
    public static void removeListeners (Object o, String listenerName, String[] packages) {
        Class oc = o.getClass();
        try {
            Method getListenersMethod = oc.getMethod("get"+listenerName+"Listeners",(Class[])null);
            String[] p;
            if (packages == null) {
                p = allPackages;
            } else {
                p = packages;
            }

            // Find the listener Class
            Class listenerClass = null;
            int pIndex = 0;
            while (listenerClass == null && pIndex < p.length) {
                try {
                    listenerClass = Class.forName(p[pIndex]+listenerName+"Listener");
                } catch (Exception ex) {
                    /* Ignore */
                }
                pIndex++;
            }
            if (listenerClass == null) {
                return; // Couldn't find the class for this listener type
            }

            Method removeListenerMethod = oc.getMethod("remove"+listenerName+"Listener", new Class[] { listenerClass });
            if (getListenersMethod != null) {
                    //res1 = m.invoke(dto1,(Object[])null);

                Object els = getListenersMethod.invoke(o,(Object[])null);
                if (els instanceof EventListener[]) {
                    EventListener[] listeners = (EventListener[])els;
                    for (int i = 0; i < listeners.length; i++) {
                        removeListenerMethod.invoke(o, new Object[] { listeners[i] });
                    }
                }
            }
        } catch (Exception e) {
            // Ignore
        }
    }

    private static String[] allListeners = { "Action","Adjustment","Ancestor","AWTEvent","BeanContextMembership","BeanContextServiceRevoked"
            ,"BeanContextServices","Caret","CellEditor","Change","Component","ConnectionEvent","Container","ControllerEvent"
            ,"Document","DragGesture","DragSource","DragSourceMotion","DropTarget","Focus","HandshakeCompleted","HierarchyBounds"
            ,"Hierarchy","Hyperlink","IIOReadProgress","IIOReadUpdate","IIOReadWarning","IIOWriteProgress","IIOWriteWarning"
            ,"InputMethod","InternalFrame","Item","Key","Line","ListData","ListSelection","MenuDragMouse","MenuKey","Menu"
            ,"MetaEvent","MouseInput","Mouse","MouseMotion","MouseWheel","NamespaceChange","Naming","NodeChange","ObjectChange"
            ,"PopupMenu","PreferenceChange","PropertyChange","RowSet","SSLSessionBinding","TableColumnModel","TableModel"
            ,"Text","TreeExpansion","TreeModel","TreeSelection","TreeWillExpand","UndoableEdit","UnsolicitedNotification"
            ,"VetoableChange","WindowFocus","Window","WindowState" } ;

    public static void removeAllListeners(Component c, String[] listeners, String[] packages) {
        String[] l;
        if (listeners == null) {
            l = allListeners;
        } else {
            l = listeners;
        }
        for (int i = 0; i < l.length; i++) {
            removeListeners(c,l[i],packages);
        }
    }

    public static void annihilateComponent(Object o, String[] listeners, String[] packages) {
        if (o == null) {
            return;
        }
        if (o instanceof Container) {
            Component[] c = ((Container)o).getComponents();
            for (int i = 0; i < c.length; i++) {
                annihilateComponent(c[i],listeners,packages);
            }
            ((Container)o).setLayout(null);
            ((Container)o).setFocusTraversalPolicy(null);
            ((Container)o).removeAll();
        }
        if (o instanceof javax.swing.JScrollPane) {
            ((javax.swing.JScrollPane)o).setViewportView(null);
        }
        if (o instanceof Component) {
            removeAllListeners((Component)o,listeners,packages);
        }
        if (o instanceof Window) {
            ((Window)o).dispose();
        }
    }

    public static void annihilateComponent(Object o) {
        annihilateComponent(o,null,null);
    }
}

我只是好奇,为什么要将所有这些组件都标记为“最终”。您真的只想将这些值指定一次,还是想获得一些性能增益?另外,我们在“buildGUI()”方法中讨论了多少GUI组件?还要5个?100多?还有100万?responsePanel是否有定制布局?我在eclipse中使用SWTDesign工具,因此它会自动为GUI生成代码,这就是为什么所有内容都标记为final。实际上,GUI组件永远不应该改变,因为它是一种只输出的东西。响应面板为GridBagLayout。仍然不知道如何解决此问题。只是想知道为什么要将所有这些组件标记为“最终”。您真的只希望这些值分配一次,还是想获得一些性能增益?另外,我们在“buildGUI()”方法中讨论了多少GUI组件?还要5个?100多?还有100万?responsePanel是否有定制布局?我在eclipse中使用SWTDesign工具,因此它会自动为GUI生成代码,这就是为什么所有内容都标记为final。实际上,GUI组件永远不应该改变,因为它是一种只输出的东西。响应面板为GridBagLayout。仍然不知道如何解决这个问题。