gpt4 book ai didi

java - Swing Timer 不被垃圾回收

转载 作者:行者123 更新时间:2023-11-30 02:27:59 26 4
gpt4 key购买 nike

由于 Swing Timer,我在 Swing 应用程序中遇到了内存泄漏问题.

我使用计时器在Page1中显示图像的幻灯片。

当我分析应用程序时,我注意到导航到 Page2 时,Timer 对象、Page1 对象以及 Page1 对象中的任何对象都没有被垃圾收集。

我开始知道stopping计时器允许它被垃圾收集。

我假设如果任何对象没有被引用,则它已准备好进行垃圾收集。但这个假设在本例中失败了。

下面的代码总结了我的应用程序,并且没有内存泄漏。要查看内存泄漏,请注释我调用 TimerstopTimer 方法的行。

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");
}

可能的原因是什么?

最佳答案

我在一个人为的小堆中分析了您的示例,如图所示here 。配置文件显示了预期的结果:定期垃圾收集将已用堆空间返回到基线,如图 here 所示。 。选择第二页作为轮廓的后半部分会导致较小的幅度收集。内存采样显示,第一页上出现的 Timer 实例在第二页上被立即收集;没有实例激增。一些额外的建议:

image

Comment [out] the line where I have called [the] stopTimer() method.

结果相同。请注意 Swing Timer 的实例“共享相同的、预先存在的计时器线程。”当 Timer 运行时,内部类 DoPostEvent 的实例出现在探查器中的名称为 javax.swing.Timer$1 的,将暂时累积。它们也将被收集,尽管最终是在垃圾收集的后期阶段。按照建议here ,您可以单击执行GC按钮来实现更积极的收集。单击 Sampler 选项卡中的 Deltas 按钮可查看在执行计时器的 ActionListener 过程中瞬时累积的其他实例;再次点击执行GC查看效果。

控制台:

$ jvisualvm &
$ java TimerMemoryLeak.java
$ java -Xms32m -Xmx32m TimerMemoryLeak

代码,经测试:

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() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
showPanel1();
frame.setSize(600, 400);
frame.setVisible(true);
}

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();
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;

private static 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);
}

private static 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");
}
}

关于java - Swing Timer 不被垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45121837/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com