Swing TimerのためにSwingアプリケーションでメモリリークの問題が発生しました。スイングタイマーはガベージコレクションされていません
私は、タイマーを使用して画像のスライドショーをPage1に表示しました。
Page2に移動すると、Timerオブジェクト、Page1オブジェクト、およびPage1オブジェクト内のオブジェクトはガベージコレクトされていないことに気付きました。
私は、stoppingがタイマーによってガベージコレクションされることができることを知りました。
オブジェクトが参照されていない場合は、ガベージコレクションの準備が整っていると仮定していました。しかし、この仮定はこのケースでは失敗しました。
以下のコードは私のアプリケーションをまとめたもので、メモリリークはありません。メモリリークを確認するには、stopTimer
というメソッドをTimer
という名前の行にコメントします。
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class TimerMemoryLeak {
public static void main(String[] args) {
TimerMemoryLeak timer = new TimerMemoryLeak();
timer.buildUI();
}
public void buildUI() {
showPanel1();
frame.setSize(600, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void showPanel1() {
Page1 page1 = new Page1();
if (currentPanel != null) {
pane.remove(((Page2) currentPanel).getPanel());
}
pane.add(page1.getPanel());
currentPanel = page1;
page1.startTimer();
page1.setNextAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showPanel2();
}
});
pane.revalidate();
pane.repaint();
}
public void showPanel2() {
Page2 page2 = new Page2();
if (currentPanel != null) {
((Page1) currentPanel).stopTimer(); // Comment this for memory leak
pane.remove(((Page1) currentPanel).getPanel());
}
pane.add(page2.getPanel());
currentPanel = page2;
page2.setPreviousAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showPanel1();
}
});
pane.revalidate();
pane.repaint();
}
private JFrame frame = new JFrame();
private Container pane = frame.getContentPane();
private Object currentPanel;
}
class Page1 {
public Page1() {
panel.add(title, BorderLayout.NORTH);
panel.add(textTimer);
panel.add(btnNext, BorderLayout.SOUTH);
}
public void setNextAction(ActionListener listener) {
btnNext.addActionListener(listener);
}
public JPanel getPanel() {
return panel;
}
public void startTimer() {
timer.setInitialDelay(0);
timer.start();
}
public void stopTimer() {
timer.stop();
}
private JPanel panel = new JPanel(new BorderLayout());
private JLabel title = new JLabel("Panel 1");
private JButton btnNext = new JButton("Next");
private JLabel textTimer = new JLabel();
private int timerInterval = 1000;
private ActionListener timerAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textTimer.setText(Math.random() + "");
}
};
private Timer timer = new Timer(timerInterval, timerAction);
}
class Page2 {
public Page2() {
panel.add(title, BorderLayout.NORTH);
panel.add(btnPrev, BorderLayout.SOUTH);
}
public void setPreviousAction(ActionListener listener) {
btnPrev.addActionListener(listener);
}
public JPanel getPanel() {
return panel;
}
private JPanel panel = new JPanel(new BorderLayout());
private JLabel title = new JLabel("Panel 2");
private JButton btnPrev = new JButton("Previous");
}
これにはどのような原因が考えられますか?
* "私はメモリリークの問題に出くわした.." *メモリリークの確認するための唯一の方法は、 'ですOutOfMEmoryError'。アプリはありますか? 1つを投げる?ガベージコレクタは、収集するものについては非常に保守的であることが知られており、頻繁に行う必要がある場合にのみ動作します。 –
[here](https://stackoverflow.com/a/45124503/230513)に示すように、リークを特定できませんでした。 – trashgod
@AndrewThompson Netbeansでプロファイリングする間に、ライブオブジェクトの数を見ることができます。 'OutOfMemoryError'はメモリリークを確認する唯一の方法ではありませんが、最終的に発生します。また、私は質問のコードの説明に追加しました。 – Barun