各位朋友你们好,在Swing程序中使用dbcp连接池commons-dbcp-1.2.2.jar,commons-collections-3.2.jar,mysql-connector-java-5.0.8-bin.jar来管理数据库连接,每次搜索数据库基本信息(只检索一条记录)程序都会新增25个com.mysql.jdbc.Statement,使用System.gc()也不能回收,当程序一直使用一直搜索可以增加到50000个statement直到程序outofmemory。调整vm的参数不能根本解决问题。
使用JProfiler来进行监控分析,并且使用它的垃圾回收也一样不能回收这些Statement物件,在每次DB查询方法中,都会使用以下语句来保证RecordSet和Statement会关闭并置NULL。
     } finally {
         if (rs != null) {
            try {
               rs.close();
            }
            catch (SQLException sqle) {
               sqle.printStackTrace();
               logger.warn("RELEASE RESULT SET ERROR IN "+this.getClass().getName()+" : "+sqle.getMessage()+", and throws RuntimeException !");
               System.err.println("RELEASE RESULT SET ERROR IN "+this.getClass().getName()+" : "+sqle.getMessage()+", and throws RuntimeException !");
               throw new RuntimeException("RELEASE RESULT SET ERROR");
            }
            rs = null;
         }
         if (stmt != null) {
            try {
               stmt.close();
            }
            catch (SQLException sqle) {
               sqle.printStackTrace();
               logger.warn("RELEASE STATEMENT ERROR IN "+this.getClass().getName()+" : "+sqle.getMessage()+", and throws RuntimeException !");
               System.err.println("RELEASE STATEMENT ERROR IN "+this.getClass().getName()+" : "+sqle.getMessage()+", and throws RuntimeException !");
               throw new RuntimeException("RELEASE STATEMENT ERROR");
            }
            stmt = null;
         }
      }
结果是不起任何的作用,只要检索数据库所有被创建的Statement都会继续保留在java heap中,一直到outofmemory。请各位老师帮帮想想办法,看怎么解决看似不可能出现的问题,谢谢!!

解决方案 »

  1.   

    我好像在finally里面没有看到关闭数据库连接的地方。
      

  2.   

    感谢楼上答复,数据库connection是一直和application一起存在,即应用程序一打开就默认新建connection供使用,当要关闭app时才会关闭conneciton.我们使用的是JInternalFrame MDI显示方式,每个不同的模组使用各自的connection,模组关闭connection会close.
      

  3.   

    这种情况只出现在查巡处理吗,update,delete会发生吗
      

  4.   

    你的代码没发现问题。但我怀疑你在
    try{} 里面有重复的stmt,比如
    try{
      stmt = con.createStatement(....);  ...
      stmt = con.createStatement(....);
      ....
      

  5.   

    应该采用
    try{
      stmt = con.createStatement(....);
      ...
      stmt.close(); // 记得关闭  stmt = con.createStatement(....);
      ....
      

  6.   

    谢谢!只在query时会有这种现象,且query的方法中也没有重复创建statement,因为每个方法中都是自行调用一次
    stmt = conn.createStatement(),然后在finally中stmt.close掉。
    当前所知道的,关闭掉连接可以消除这些Statement,但连接不允许被关闭掉,因为使用提dbcp连接池,他应该可以很好的来管理Statement的生命周期,问题应该出现在程序中,但又想不出来方法的局部变量怎么会在使用完后,不能被释放。
      

  7.   

    在query和delete,update方法中都有此现象,当前我们只是大量测试query这样问题看起来比较明显。
      

  8.   

    关闭掉连接可以消除这些Statement,但连接不允许被关闭掉为什么不允许被关掉
    conn.close(); //  一定要调用的,我还奇怪你的代码里面怎么没有这一句呢!!!!!!!!因为你用的是连接池,不用担心close()会真的把数据库物理连接给断掉了,
    连接池已经重写这个close()方法,他只是把连接标识为可用状态,然后可以提供给下一个 getConnection使用而已。一定要关闭,切记切记!!
      

  9.   

    在query和delete,update方法中都有此现象,我想应该是connection没有关闭造成的,
    不论怎样,你可以先试着对数据库操作完毕就关闭连接,看看改过之后是否还有这种现象我接触过的程序不论是否使用连接池,全都是数据库操作完毕就关连接,不明白你们那样做的理由是什么
      

  10.   

    感谢,我们的情况是这样,我们的程序使用的是JInternalFrame这样在一个主Frame中可以同时打开多个InternalFrame的方式,我们现在的做法是,当子frame初始化我们就将此子frame所使用到的connection新建起来,这样所有的在此子frame中要使用的service都全部传递此同一个connection,同一connection在此子frame中的多个class中都有拷贝,所以不能关闭此connection否则整个画面frame都必须关掉 或者 出现connection=null的错误。
    在程序出现outofmemory错误的情况下,我使用jdk6中自带的jmap和jhat工具查出占heap内存容量的前几位如下,因为图不能贴上来就直接幅文字了,
    共三列,第一列是class,第二列是instance count实例个数,第三列是实例所占内存
    各位请看:第一行“class [I”占用的heap内存最多,41461个实例占达到456M内存,但现在不知道他是怎么被生出来的,请求各位帮助
    Heap HistogramAll Classes (excluding platform)
    Class  Instance Count  Total Size
    class [I  41461  456128144
    class [C  102576  6951982
    class [Ljava.lang.Object;  154684  4995856
    class javax.swing.JButton  7102  3060962
    class javax.swing.JPanel  9730  3035760
    class java.util.Hashtable$Entry  171144  2738304
    class pics.system.val.Acc  3440  1723440
    class [Ljava.util.Hashtable$Entry;  18812  1552152
    class javax.swing.JMenuItem  3556  1550416
    class java.lang.String  96832  1549312
    class javax.swing.JLabel  4162  1485834
    class com.mysql.jdbc.Statement  13783  1171555
    class javax.swing.JPopupMenu$Separator  3429  1083564
    class [B  1703  977251
    class javax.swing.JTextField  2192  960096
    class javax.swing.JMenu$1  1940  853600
    class com.incors.plaf.alloy.dk  1940  836140
    class java.awt.Color  24540  785280
    class javax.swing.JPopupMenu  2227  770542
    class pics.gui.share.linkaccess.JFocusSelTextField  1709  748542
    class [Ljava.awt.Component;  48523  608972
    class java.util.WeakHashMap$Entry  21744  608832
    class java.util.Hashtable  18793  601376我利用jhat提供的分析方法来分析class [I到底是怎么增加到这么多的,一头雾水,因为连接到class [I的实例种类有很多如下图:
    共2列:第一列是class名称,第二列是实例个数
    References by Typeclass [I [0x2b79ef98]
    Referrers by TypeClass Count
    javax.swing.plaf.basic.BasicTextUI$BasicCaret  10228
    java.awt.image.SinglePixelPackedSampleModel  5238
    java.util.GregorianCalendar  3792
    sun.awt.image.IntegerInterleavedRaster  3492
    java.awt.image.DataBufferInt  3462
    javax.swing.text.ParagraphView$Row  2188
    javax.swing.text.html.ParagraphView  2184
    javax.swing.text.html.HTMLEditorKit$HTMLFactory$1  2060
    javax.swing.text.html.BlockView  2060
    javax.swing.text.html.HTMLEditorKit$HTMLFactory$BodyBlockView  2060
    [[I  1970
    java.awt.image.DirectColorModel  1500
    java.awt.GridBagLayoutInfo  968
    sun.util.calendar.ZoneInfo  741
    javax.swing.text.html.StyleSheet  517
    javax.swing.plaf.basic.BasicSplitPaneUI$BasicHorizontalLayoutManager  244
    java.math.BigInteger  77
    java.lang.Class  50
    sun.font.CompositeFont  40
    java.awt.image.IndexColorModel  36
    com.incors.plaf.n  23
    java.awt.image.PixelInterleavedSampleModel  22
    sun.awt.image.ImageRepresentation  11
    java.awt.image.DataBufferByte  11
    sun.awt.image.ByteInterleavedRaster  11
    sun.font.FileFontStrike  10
    sun.font.FontStrikeDisposer  10
    sun.awt.FontDescriptor  8
    java.util.regex.Pattern$Slice  4
    java.util.Hashtable$Entry  4
    sun.nio.ch.WindowsSelectorImpl$SubSelector  3
    org.apache.log4j.RollingCalendar  3
    sun.font.GlyphList  2
    com.incors.plaf.alloy.AlloyListUI  2
    com.incors.plaf.alloy.a.g  2
    com.incors.plaf.alloy.a.e  1
    java.awt.Toolkit$SelectiveAWTEventListener  1
    javax.swing.JComponent$IntVector  1
    sun.awt.windows.WFontConfiguration  1
    sun.awt.windows.WToolkit  1请教我应该怎么来查找问题,谢谢
      

  11.   

    关于Statement增多的问题,基本上已经解决了,是DAO中一个构造方法stmt创建后没有被关闭掉,现已经修正。
    问题依旧,程序在多次连续运行下依然会出outofmemory现象如楼上的回复。造成生出这么多class [I,真的是因为connection一直没有被关闭的原因吗?真希望是,这样就能确认问题了。
      

  12.   

    也不清楚 class [I 究竟代表是什么类型,只知道他的父类是java.lang.Object
      

  13.   

    heap中还有好多以下这样的对象B,C,D,F等,不知道是什么意思,谢谢
    Heap HistogramAll Classes (excluding platform)
    Class  Instance Count  Total Size
    class [B  1703  977251
    class [C  102576  6951982
    class [D  1003  24880
    class [F  542  23904
    class [I  41461  456128144
    class [J  298  6264
    class [Lcom.mysql.jdbc.Field;  0  0
    class [Lcom.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache$Entry;  1  4104
    class [Ljava.awt.AWTKeyStroke;  4  48
    class [Ljava.awt.Color;  24  436
    class [Ljava.awt.Component;  48523  608972
    class [Ljava.awt.Container;  0  0class [Lsun.util.calendar.Era;  2  32
    class [S  2347  165720
    class [Z  1298  34073
    class [[B  11  132
    class [[C  104  1684
    class [[D  1  76
    class [[I  1743  24416
    class [[J  1  64
    class [[Ljava.awt.AWTKeyStroke;
      

  14.   

    java2000_net赵老师您好,您讲的重点我自己做了些总结,您看对不对?1、   不要共用一个connection, 因为使用连接池,重新获得connection很轻松不用担心性能问题,每个查询方法新建自己的connection使用完后都要立即关闭所有资源(包括连接),即一次扫描动作要检索数据库1000次,每次都要使用自己的connection,随即new随即close。
    a)        只有事务才需要共用connection,无论怎样,不能一直占用一个connection,用完及时关闭
    2、   检查程序里用到的static Map, static List, static set这些地方,很可能你只往里面增加数据,而忘了删除没用的数据,所以要注意及时释放资源;
    3、   先将程序调正确,再考虑性能方面,关于cache可以先屏蔽掉,调正确再来调优;这些辅助如果用不好亦会占用大量内存。
    4、   类名“Class [I”表示是int [ ]数组,在使用jmap和jhat追踪jvm占用heap内存时, 当前的问题就是Class [ I (即int [ ])会累计占用80%的vm heap内存。
    5、   检查int [ ] 去找那些类一级或者是static变量,或者是这些int[] 肯定被放到了某些 list / map/set 里面了,造成他们占用的内存不会被释放;
    6、   程序中使用hashmap和hashtable太多,使用完后要立即释放资源,即可调用map.clear可加快程序
    7、   去检查扫描动作中动态使用的ArrayList是否正确释放,等等非常感谢您的帮助,到现在问题在一点点的显现,年前可能是没办法解决了,要到年后了,准备要放假回家了。
    祝您新年快乐,年后15号开始此问题持续追踪,直到找到解决方式。
    给所有朋友问声好,祝所有的朋友幸福安康!
      

  15.   

    新年好,这几天主要是对非法的静态变量和非法关联做了部分修正,程序的效能有很大提升,到outofmemory的效能提升了约3倍。
    主要的问题还是静态变量和程序中的非法关联导致本该被回收的对象一直被关联,无法被GC回收。问题还在持续改进中...
      

  16.   

    到结贴时间了,谢谢大家的帮助,尤其感谢java2000_net赵老师,谢谢!