假设我是子类JPanel
,而我的子类使用了大量内存。
我设计这个类的正确方法是什么,以便在我的JPanel用作更大系统中的组件时释放内存资源?
似乎有几个选择:
finalize()
(遍布各地的红旗 - 我读过的文献说你不应该进入最终的业务)。dispose()
或destroy()
或其他内容在下面的示例中,我使用了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);
}
}
答案 0 :(得分:4)
最佳解决方案是向JPanel添加HierarchyListener
,然后检查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);
}
}
答案 1 :(得分:0)
就像你提到的那样,不要调用finalize(),这只是危险而且很难做到。
我总是添加dispose方法来处理监听器清理和删除任何内存密集型资源。我认为正确地做到这一点的诀窍是,应该有一种处理器来破坏这些对象。
如果您正在谈论将在更通用的框架中使用的更通用的组件,这可能不是正确的解决方案