2011-10-28 2 views
5

Une application Swing (GUI), une destination un terminal d'information de destination. Le profileur VirtualVM montre que la fuite se produit en raison deFuite de mémoire dans Swing

java.awt.image.DataBufferInt 

и

sun.awt.image.ImageRepresentation.setPixels 

, l'augmentation de la mémoire se produit au cours des transitions entre les formes.

La logique d'application est qu'il existe plusieurs formes (JFrame - JF1, JF2 ... JF7). Formulaire de base JF1, en appuyant sur les boutons J ouvrir d'autres formes, et se ferme, etc. Sauf JF1 toutes les autres formes ont des boutons <>. Dans les formes il y a beaucoup JButton avec les images, utilisées 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); 
    } 
} 

Les JButton sur les formulaires sont rédigés comme suit:

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

La classe principale qui commence d'abord:

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

Toujours dans Init méthode de Forms a une minuterie qui, après un certain temps, ouvre le formulaire principal et ferme le formulaire en cours:

... 
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 Veuillez corriger une fuite de mémoire.

j'avais changé tout panneau à JPanel et est le code de 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(); 
    } 
} 

Et c'est nouveau dump

+1

Pourriez-vous s'il vous plaît expliquer comment vous êtes arrivé à la conclusion que c'est une fuite? Est-ce juste parce que la mémoire se développe? Parce que cela peut simplement signifier que le garbage collector n'a pas encore fonctionné. Sauf si vous donnez des mesures plus significatives (et non, je ne télécharge pas de fichier rar sur rapidshare), il n'y a vraiment aucun moyen d'aider. –

+0

En raison de OutOfMemoryError. Et je le surveille par VirtualVM – Daler

Répondre

4

Vous avez une fuite, mais le simple fait de regarder le nombre de classes chargées ne vous aidera pas à déterminer de quoi il s'agit.

Si vous chargez votre instantané dans JProfiler (disclaimer: mon entreprise se développe JProfiler) et regarder le plus grand écran des objets, vous pouvez voir que la mémoire utilisée est due à la double mise en mémoire tampon des multiples JF1 cadres et les instances de panneau qui appartiennent à ces cadres.

enter image description here

Votre problème est que les JF1 cadres sont cachés mais non aliénées. Une recherche de racines GC montre que les 3 cadres invisibles sont contenus dans java.awt.Window.allWindows, ce qui ne peut pas être le cas si dispose() est appelée. Vous appelez beaucoup de code en dehors du thread d'envoi d'événement. Par exemple, vous ne devez pas appeler setVisible() depuis le thread du minuteur. Essayez d'imprimer la création des trames JF1 et l'appel à leurs méthodes d'élimination et vérifiez où elles ne correspondent pas.

enter image description here

+0

C'est là que je dispose JF1 if (GlobalVars.jf3 == null) GlobalVars.jf3 = nouveau JF3(); GlobalVars.jf3.init(); GlobalVars.jf3.setVisible (true); // Так открывается новая форма setVisible (false); // и закрывается текущая dispose(); – Daler

+0

Ensuite, ces lignes ne sont pas appelées. Essayez d'imprimer la création de JF1s et leur élimination et vérifiez s'ils correspondent. –

+0

J'ai ajouté le code JF1 et le nouveau vidage – Daler

3

vous créez beaucoup de Top-level Containers, avec JComponents ou Images l'intérieur d'eux, et ceux-ci Objects en cette forme n'a jamais disparu pour JVM Used_Memory, vous devez nettoyer le contenu de Top-level Containers,

mieux serait

créer JFrame une seule fois, et pour une autre fenêtre pop-up créer un seul JDialog/JWindow mis ici JPanel, réutiliser ce conteneur en retirant JComponents de JPanel,

JPanel.removeAll(); 

DefaultCloseOperation serait

JDialog#setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE)

ou vous pouvez définir

JDialog#setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE) et vous pouvez appeler uniquement

JDialog#setVisible(false/true) 

EDIT

et vous devez fermer toutes JDBC ResultSet, Déclaration, PreparedStatement en bloc finally, parce que ces objets ne disparu de JVM UsedMemory trop