Swing中的内存泄漏

时间:2011-10-28 06:04:22

标签: java swing memory-leaks

应用程序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

2 个答案:

答案 0 :(得分:4)

你确实有泄漏,但只是查看已加载的类的数量将无法帮助你找出它是什么。

如果您在JProfiler(免责声明:我的公司开发JProfiler)中加载您的快照并查看最大的对象视图,您可以看到使用的内存是由于倍{{1}的双重缓冲框架以及属于这些框架的面板实例。

enter image description here

您的问题是 JF1帧被隐藏但未被丢弃。对GC根的搜索显示JF1中包含所有3个不可见帧,如果调用java.awt.Window.allWindows则不然。你在事件派遣线程之外调用了很多代码。例如,您不应该从计时器线程调用setVisible()。尝试打印出JF1帧的创建和对其dispose方法的调用,并检查它们不匹配的位置。

enter image description here

答案 1 :(得分:3)

你创建了很多Top-level Containers,其中包含JComponentsImages,这些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中删除