应用程序Swing(GUI),目的地是目的地信息终端。 VirtualVM Profiler显示由于
而发生泄漏java.awt.image.DataBufferInt
и
sun.awt.image.ImageRepresentation.setPixels
,在表单之间的转换期间发生内存增加。
应用程序逻辑是有几种形式(JFrame - JF1,JF2 ... JF7)。 JF1基本形式,按JButtons打开其他形式,并自行关闭等。除了JF1,所有其他形式都有按钮<>。在表单中有许多带有图片的JButton,使用FancyButton:
public class FancyButton extends JButton {
private static final long serialVersionUID = 1L;
public FancyButton(Icon icon, Icon pressed) {
super(icon);
setFocusPainted(false);
//setRolloverEnabled(treue);
//setRolloverIcon(rollover);
setPressedIcon(pressed);
setBorderPainted(false);
setContentAreaFilled(false);
}
}
表单上的JButton如下所示:
public class JF1 extends JFrame {
private static final GridBagConstraints gbc;
public static Timer tmr;
public JF1() throws Exception{
setUndecorated(true);
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
setAlwaysOnTop(true);
setLayout(new GridBagLayout());
setTitle("JF1");
}
public void init() throws Exception{
GlobalVars.jf2 = null;
GlobalVars.jf3 = null;
GlobalVars.jf4 = null;
GlobalVars.jf5 = null;
GlobalVars.jf6 = null;
GlobalVars.jf7 = null;
JXPanel contentPane = new JXPanel();
try {
ImagePainter ip = new ImagePainter(ImageIO.read(new File("skins/bg.jpg")));
ip.setFillHorizontal(true);
ip.setFillVertical(true);
contentPane.setBackgroundPainter(ip);
} catch (Exception e) {
e.printStackTrace();
}
Panel p01 = new Panel();
GridLayout gl01 = new GridLayout(1, 8, 2, 2);
p01.setLayout(gl01);
p01.setLocation(200, 300);
ResultSet rs = GlobalVars.st.executeQuery("select * from last_use_service order by nomer");
Icon i1;
Icon i2;
while (rs.next()){
final int l = rs.getInt(2);
i1 = new ImageIcon("skins/oper_logos/" + l + ".png");
i2 = new ImageIcon("skins/oper_logos/" + l + "_off.png");
FancyButton jbt = new FancyButton(i1,i2 );
jbt.setBounds(10, 100, 100, 100);
jbt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
tmr.stop();
if(GlobalVars.jf3==null)
GlobalVars.jf3 = new JF3();
GlobalVars.jf3.init();
GlobalVars.jf3.setVisible(true); // Так открывается новая форма
setVisible(false); // и закрывается текущая
dispose();
}
});
p01.add(jbt);
}
rs.close();
addComponent(panel, p01, 0, 1, 2, 1, GridBagConstraints.WEST,GridBagConstraints.NORTHWEST);
...
首先开始的主要课程:
public class Main {
public static class GlobalVars{
public static String TypeDB = "MySQL";
public static Connection DataBase;
public static Statement st;
public static JF1 jf1; // JFrame
public static JF2 jf2; // JFrame
public static JF3 jf3; // JFrame
...
}
public static void main(String[] args) throws Exception {
if(GlobalVars.TypeDB.equals("MySQL")){
Class.forName("com.mysql.jdbc.Driver");
GlobalVars.DataBase = DriverManager.getConnection("jdbc:mysql://localhost:3306/terminal?lc_ctype=UTF8", "root","123");
if(GlobalVars.jf1==null)
GlobalVars.jf1 = new JF1();
GlobalVars.jf1.init();
GlobalVars.jf1.setVisible(true);
}
...
}
仍然在Init方法中,Forms有一个计时器,一段时间后打开主表单并关闭当前表单:
...
tmr = new Timer( s * 1000, updateCursorAction);
tmr.start();
...
private Action updateCursorAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if(GlobalVars.jf1==null){
try {
GlobalVars.jf1= new JF1();
} catch (Exception e1) {
e1.printStackTrace();
}
}
tmr.stop();
try {
GlobalVars.jf1.init();
} catch (Exception e1) {
e1.printStackTrace();
}
GlobalVars.jf1.setVisible(true);
GlobalVars.jf2 = null;
setVisible(false);
dispose();
}
};
HEAP DUMP 请帮助修复内存泄漏。
我已将所有Panel更改为JPanel,这是JF1的代码:
package PlatService;
import java.awt.*;
public class JF1 extends JFrame {
private static final long serialVersionUID = 1L;
//private static final Insets insets = new Insets(0, 0, 0, 0);
private static String[] arrLang = { "rus", "eng", "taj" };
private static final GridBagConstraints gbc;
public static Timer tmr;
static {
public JF1() throws Exception{
setUndecorated(true);
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
setAlwaysOnTop(true);
setLayout(new GridBagLayout());
setTitle("JF1");
}
public void init() throws Exception{
GlobalVars.jf2 = null;
GlobalVars.jf3 = null;
GlobalVars.jf4 = null;
GlobalVars.jf5 = null;
GlobalVars.jf6 = null;
GlobalVars.jf7 = null;
JXPanel contentPane = new JXPanel();
try {
ImagePainter ip = new ImagePainter(ImageIO.read(new File("skins/bg.jpg")));
ip.setFillHorizontal(true);
ip.setFillVertical(true);
contentPane.setBackgroundPainter(ip);
} catch (Exception e) {
e.printStackTrace();
}
//setContentPane(contentPane);
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
addComponent(this, panel, 0, 0, 1, 1, GridBagConstraints.CENTER ,GridBagConstraints.BOTH);
JPanel p0 = new JPanel();
GridLayout gl0 = new GridLayout(1, 1, 1, 1);
final JLabel jl = new JLabel(new ImageIcon("skins/logo.png"));
p0.setLayout(gl0);
p0.add(jl);
addComponent(panel, p0, 0, 0, 2, 1, GridBagConstraints.NORTH ,GridBagConstraints.NORTH);
JPanel p01 = new JPanel();
GridLayout gl01 = new GridLayout(1, 8, 2, 2);
p01.setLayout(gl01);
p01.setLocation(200, 300);
ResultSet rs = GlobalVars.st.executeQuery("select * from last_use_service order by nomer");
Icon i1;
Icon i2;
while (rs.next()){
final int l = rs.getInt(2);
i1 = new ImageIcon("skins/oper_logos/" + l + ".png");
i2 = new ImageIcon("skins/oper_logos/" + l + "_off.png");
FancyButton jbt = new FancyButton(i1,i2 );
jbt.setBounds(10, 100, 100, 100);
jbt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
tmr.stop();
GlobalVars.OperId = l;
GlobalVars.getCashCode=false;
if(GlobalVars.jf3==null)GlobalVars.jf3 = new JF3();
GlobalVars.jf3.init(); // = new JF3();
GlobalVars.jf3.setVisible(true);
setVisible(false);
dispose();
}
});
p01.add(jbt);
}
rs.close();
addComponent(panel, p01, 0, 1, 2, 1, GridBagConstraints.WEST,GridBagConstraints.NORTHWEST);
if (GlobalVars.LangId < 0 || GlobalVars.LangId > 2)GlobalVars.LangId = 0;
String sql = "SELECT * FROM OpGroup WHERE parent=0 order by enable desc, order_n";
PreparedStatement psmnt = GlobalVars.DataBase.prepareStatement(sql);
ResultSet rs2 = psmnt.executeQuery();
//rs = GlobalVars.st.executeQuery();
JPanel p = new JPanel();
GridLayout gl = new GridLayout(0, 2, 2, 2);
p.setLayout(gl);
p.setSize(300, 400);
p.setLocation(200, 300);
while (rs2.next()){
final int l = rs2.getInt(2);
i1 = new ImageIcon("skins/"+ arrLang[GlobalVars.LangId]+"/services/" + l + ".png");
i2 = new ImageIcon("skins/"+ arrLang[GlobalVars.LangId]+"/services/" + l + "_off.png");
FancyButton jbt = new FancyButton(i1,i2);
jbt.setBounds(10, 100, 100, 100);
if(rs2.getInt("enable")==1){
jbt.setEnabled(true);
}else{
jbt.setEnabled(false);
}
jbt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
GlobalVars.getCashCode=false;
try {
tmr.stop();
ActionPerformed(event, GlobalVars.LangId, l);
} catch (Exception e) {
e.printStackTrace();
}
}
});
p.add(jbt);
}
addComponent(panel, p, 0, 2, 1, 1, GridBagConstraints.NORTH,GridBagConstraints.NORTH);
rs2.close();
JPanel p1 = new JPanel();
GridLayout gl1 = new GridLayout(5, 1, 5, 5);
// setLayout(new GridLayout(3, 4, 2, 2));
p1.setLayout(gl1);
// p2.setSize(300, 400);
// p2.setLocation(200, 300);
for (int i = 0; i < arrLang.length; i++) {
final int l = i;
i1 = new ImageIcon("skins/button_" + arrLang[i] + ".png");
i2 = new ImageIcon("skins/button_" + arrLang[i] + "_off.png");
FancyButton jbt = new FancyButton(i1, i2);
jbt.setBounds(10, 100, 100, 100);
//if (i == GlobalVars.LangId) {jbt.setEnabled(false);}
jbt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
//Play.stop();
GlobalVars.LangId = l;
GlobalVars.getCashCode=false;
GlobalVars.jf1 = null;
try {
GlobalVars.jf1 = new JF1();
} catch (Exception e1) {
e1.printStackTrace();
}
try {
GlobalVars.jf1.init();
} catch (Exception e) {
e.printStackTrace();
}
tmr.stop();
GlobalVars.jf1.setVisible(true);
setVisible(false);
}
});
p1.add(jbt);
}
i1 = new ImageIcon("skins/" + arrLang[GlobalVars.LangId] + "/services/button_help.png");
i2 = new ImageIcon("skins/" + arrLang[GlobalVars.LangId] + "/services/button_help_off.png");
FancyButton jbt_help = new FancyButton(i1,i2);
jbt_help.setBounds(10, 100, 100, 100);
jbt_help.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
tmr.stop();
GlobalVars.getCashCode=false;
GlobalVars.jf1 = null;
try {
GlobalVars.jf1 = new JF1();
} catch (Exception e1) {
e1.printStackTrace();
}
try {
GlobalVars.jf1.init();
} catch (Exception e) {
e.printStackTrace();
}
GlobalVars.jf1.setVisible(true);
setVisible(false);
}
});
p1.add(jbt_help);
i1 = new ImageIcon("skins/" + arrLang[GlobalVars.LangId] + "/services/button_about.png");
i2 = new ImageIcon("skins/" + arrLang[GlobalVars.LangId] + "/services/button_about_off.png");
FancyButton jbt_about = new FancyButton(i1,i2);
jbt_about.setBounds(10, 100, 100, 100);
p1.add(jbt_about);
addComponent(panel, p1, 1, 2, 1, 1, GridBagConstraints.EAST,GridBagConstraints.EAST);
JPanel p011 = new JPanel();
GridLayout gl011 = new GridLayout( 1, 1, 1, 1);
gl011.setVgap(1);
JLabel jl12 = new JLabel("<html><hr></html>", JLabel.LEFT);
jl12.setAlignmentX(TOP_ALIGNMENT);
jl12.setBackground(Color.red);
p011.setLayout(gl011);
p011.add(jl12);
p011.setSize(10, 90);
addComponent(panel, p011, 0, 3, 4, 1, GridBagConstraints.WEST, GridBagConstraints.NORTH);
JPanel p0112 = new JPanel();
GridLayout gl0112 = new GridLayout( 1, 1, 1, 1);
gl0112.setVgap(1);
JLabel jl122 = new JLabel("<html><hr><H2>"+GlobalVars.StatusMessage[GlobalVars.LangId]+"</H2></html>", JLabel.CENTER);
jl122.setAlignmentX(TOP_ALIGNMENT);
p0112.setLayout(gl0112);
p0112.add(jl122);
p0112.setSize(10, 90);
addComponent(this, p0112, 0, 5, 5, 1, GridBagConstraints.SOUTH, GridBagConstraints.BOTH);
if(!GlobalVars.stTerminal.equals("301")){
GlobalVars.stTerminal = "301";
String sql1 = "INSERT INTO perif_status (perif,state,date_change) values('terminal','"+GlobalVars.stTerminal+"',UNIX_TIMESTAMP())";
//System.out.println(sql1);
try {
GlobalVars.st.execute(sql1);
} catch (SQLException e) {
e.printStackTrace();
}
}
GlobalVars.NomerAb="";
GlobalVars.GroupId = 0;
GlobalVars.getCashCode=true;
tmr = new Timer(1000, updateCursorAction);
tmr.start();
System.gc();
}
public void update(){
private Action updateCursorAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if(GlobalVars.doBlock){
if(!GlobalVars.stTerminal.equals("303")){
GlobalVars.stTerminal = "303";
String sql1 = "INSERT INTO perif_status (perif,state,date_change) values('terminal','"+GlobalVars.stTerminal+"',UNIX_TIMESTAMP())";
String sql2 = "UPDATE settings set value='"+GlobalVars.stTerminal+"' WHERE variable='terminal_state'";
System.out.println(sql1);
System.out.println(sql2);
try {
GlobalVars.st.execute(sql1);
} catch (SQLException e1) {
e1.printStackTrace();
}
try {
GlobalVars.st.execute(sql2);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
String sql1 = "UPDATE commands SET status=1, date_execute=UNIX_TIMESTAMP() WHERE id_on_server="+GlobalVars.doCommandId;
System.out.println(sql1);
try {
GlobalVars.st.execute(sql1);
} catch (SQLException e1) {
e1.printStackTrace();
}
if(GlobalVars.jf7==null)
try {
GlobalVars.jf7= new JF7();
} catch (Exception e1) {
e1.printStackTrace();
}
try {
GlobalVars.jf7.init();
} catch (Exception e1) {
e1.printStackTrace();
}
GlobalVars.doBlock=false;
GlobalVars.doCommandId = 0;
GlobalVars.jf7.setVisible(true);
GlobalVars.jf1 = null;
setVisible(false);
tmr.stop();
setVisible(false);
dispose();
}
}
};
private static void addComponent(Container container, Component component,int gridx, int gridy, int gridwidth, int gridheight, int anchor,int fill) {
Insets ins = new Insets(0, 0, 0, 0);
GridBagConstraints gbc1 = new GridBagConstraints(gridx, gridy,gridwidth, gridheight, 1.0, 1.0, anchor, fill, ins, 0, 0);
container.add(component, gbc1);
}
public void ActionPerformed(ActionEvent event, int lID,int gId) throws Exception {
GlobalVars.GroupId = gId;
if(GlobalVars.jf2==null)GlobalVars.jf2 = new JF2();
GlobalVars.jf2.init();
GlobalVars.jf2.setVisible(true);
setVisible(false);
dispose();
}
}
那是新的dump
答案 0 :(得分:4)
你确实有泄漏,但只是查看已加载的类的数量将无法帮助你找出它是什么。
如果您在JProfiler(免责声明:我的公司开发JProfiler)中加载您的快照并查看最大的对象视图,您可以看到使用的内存是由于倍{{1}的双重缓冲框架以及属于这些框架的面板实例。
您的问题是 JF1
帧被隐藏但未被丢弃。对GC根的搜索显示JF1
中包含所有3个不可见帧,如果调用java.awt.Window.allWindows
则不然。你在事件派遣线程之外调用了很多代码。例如,您不应该从计时器线程调用setVisible()。尝试打印出JF1帧的创建和对其dispose方法的调用,并检查它们不匹配的位置。
答案 1 :(得分:3)
你创建了很多Top-level Containers,其中包含JComponents或Images
,这些Objects
这个形式的JVM Used_Memory
永远不会用于Top-level Containers
,你必须清除未使用的JFrame
,
更好的是
仅创建JDialog/JWindow
一次,对于另一个弹出窗口,只创建一个放置JPanel
的{{1}},通过从{{1}移除JComponents
重新使用此容器},
JPanel
DefaultCloseOperation将是
JDialog#setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE)
或者你可以设置
JPanel.removeAll();
然后你只能打电话给
JDialog#setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE)
修改
你必须关闭finally块中的所有JDBC ResultSet,Statement,PreparedStatement,因为这些Object也永远不会从JVM UsedMemory中删除