自动导致子类 JPanel 的资源被释放

Jas*_*n S 6 java resources swing

假设我对 进行子类化JPanel,并且我的子类使用了大量内存。

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

似乎有几个选择:

  1. 子类finalize()(到处都是危险信号——我读过的文献说你不应该参与最终确定业务)
  2. 添加显式的dispose()destroy()其他的,供我的班级的消费者使用
  3. 向我的 JPanel 添加某种侦听器,当父级被释放时该侦听器会收到通知
  4. 重写 JPanel 的某些方法,当其父窗口被释放时,该方法将自动被调用

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

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

选项 #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);
    }   
}
Run Code Online (Sandbox Code Playgroud)

小智 5

HierarchyListener最好的解决方案是向 JPanel添加 a ,然后检查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);

   }
}
Run Code Online (Sandbox Code Playgroud)


mev*_*ett 0

就像你提到的,不要调用 Finalize(),这很危险并且很难正确执行。

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

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