【问题标题】:automatically causing a subclassed JPanel's resources to be released自动导致子类 JPanel 的资源被释放
【发布时间】:2011-05-31 15:03:17
【问题描述】:

假设我继承了JPanel,而我的子类占用了大量内存。

我设计这个类的正确方法是什么,以便在我的 JPanel 用作更大系统中的组件时释放内存资源?

似乎有几个选项:

  1. 子类finalize()(到处都是危险信号——我读过的文献说你不应该进入最后的业务)
  2. 添加明确的dispose()destroy() 或其他任何内容,供我班的消费者使用
  3. 在我的 JPanel 中添加某种监听器,当父级被释放时会收到通知
  4. 覆盖 JPanel 的某些方法,当它们的父窗口被释放时会自动调用该方法

在下面的示例中,我使用了 finalize() 选项,该选项仅在调用垃圾收集时才有效,并且在某些情况下,我宁愿在不再需要 JPanel 时进行清理。

选项#2 不错,但是我必须依靠消费者来调用这个方法,而 Swing 的哲学似乎只是将组件粘贴到窗口中,并在窗口关闭时让所有组件销毁。因此,如果我的 JPanel 位于 JFrame 中的 JPanel 中的 JScrollPane 中的 JTable 中,那么我班级的使用者可能不会调用我的 dispose()destroy() 方法。

选项 #3 或 #4 是我的选择,但我找不到任何似乎适用于此的内容。

有什么建议吗?

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class JPanelMemoryHog extends JPanel
{
    final private String title;
    final private Object space;

    public JPanelMemoryHog(String title)
    {
        super();
        this.title = title;
        this.space = new byte[5*1000*1000];
        setBorder(BorderFactory.createTitledBorder(title));
        setPreferredSize(new Dimension(300,200));
    }

    @Override protected void finalize()
    {
        System.out.println("finalized "+this.title);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("example");
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        JButton button = new JButton("create frame");
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                createFrame();
            }
        });
        panel.add(button, BorderLayout.CENTER);
        frame.setContentPane(panel);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static int panelcount = 0;
    protected static void createFrame() {
        final String title = "panel"+(++panelcount);
        final JFrame frame = new JFrame(title);
        frame.setContentPane(new JPanelMemoryHog(title));
        frame.pack();
        frame.addWindowListener(new WindowAdapter() {
            @Override public void windowClosing(WindowEvent e) {
                System.out.println("closing "+title);
                frame.dispose();
            }
        });
        frame.setVisible(true);
    }   
}

【问题讨论】:

  • 能否将面板添加到 JDialog 中?一旦对话框关闭,它应该确保您的面板默认被垃圾收集,没有任何特定的侦听器/事件/finialise()/destroy() 混乱。
  • @emeraldjava JDialog 完全不正确,第一个从来没有被 GC 处理过,但是隧道的光给了我们这个 Woodoo 由垃圾神为 JDialog stackoverflow.com/questions/5540354/…

标签: java swing resources


【解决方案1】:

最好的解决方案是将HierarchyListener 添加到JPanel,然后检查HierarchyEvent.DISPLAYABILITY_CHANGED(当父对话框显示和处理时触发),然后检查isDisplayable() 是否为false,这是条件集在处理过程中。

public void hierarchyChanged(HierarchyEvent e) {
   //check for Hierarchy event
   if(e.getChangeFlags() == HierarchyEvent.DISPLAYABILITY_CHANGED)
   {       
        //do the required action upon close
       if(!this.isDisplayable())                         
          Notifier.removeListener(this);

   }
}

【讨论】:

  • 有趣...您能否将 isDisplayable() 链接到 Javadoc,例如docs.oracle.com/javase/7/docs/api/java/awt/… 声明“当组件从可显示的包含层次结构中移除或当其包含层次结构变得不可显示时,组件将变得不可显示。当其祖先窗口被释放时,包含层次结构将变得不可显示。”我担心的是,如果它从可显示的包含层次结构中移除,但后来放入不同的层次结构中,在这种情况下我应该处置资源。
  • 与其比较e.getChangeFlags()DISPLAYABILITY_CHANGED,不如使用按位与。
【解决方案2】:

就像你提到的,不要调用 finalize(),这很危险,而且很难正确处理。

我总是添加处理侦听器清理和删除任何内存密集型资源的处置方法。我认为正确执行此操作的诀窍是应该有某种管理器来处理销毁此类对象。

如果您正在谈论将在更通用的框架中使用的更通用的组件,这可能不是正确的解决方案

【讨论】:

    猜你喜欢
    • 2012-07-26
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 2015-09-29
    • 2012-01-08
    • 2012-05-04
    • 2011-12-31
    • 1970-01-01
    相关资源
    最近更新 更多