各位朋友你们好,在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。请各位老师帮帮想想办法,看怎么解决看似不可能出现的问题,谢谢!!
使用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。请各位老师帮帮想想办法,看怎么解决看似不可能出现的问题,谢谢!!
try{} 里面有重复的stmt,比如
try{
stmt = con.createStatement(....); ...
stmt = con.createStatement(....);
....
try{
stmt = con.createStatement(....);
...
stmt.close(); // 记得关闭 stmt = con.createStatement(....);
....
stmt = conn.createStatement(),然后在finally中stmt.close掉。
当前所知道的,关闭掉连接可以消除这些Statement,但连接不允许被关闭掉,因为使用提dbcp连接池,他应该可以很好的来管理Statement的生命周期,问题应该出现在程序中,但又想不出来方法的局部变量怎么会在使用完后,不能被释放。
conn.close(); // 一定要调用的,我还奇怪你的代码里面怎么没有这一句呢!!!!!!!!因为你用的是连接池,不用担心close()会真的把数据库物理连接给断掉了,
连接池已经重写这个close()方法,他只是把连接标识为可用状态,然后可以提供给下一个 getConnection使用而已。一定要关闭,切记切记!!
不论怎样,你可以先试着对数据库操作完毕就关闭连接,看看改过之后是否还有这种现象我接触过的程序不论是否使用连接池,全都是数据库操作完毕就关连接,不明白你们那样做的理由是什么
在程序出现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请教我应该怎么来查找问题,谢谢
问题依旧,程序在多次连续运行下依然会出outofmemory现象如楼上的回复。造成生出这么多class [I,真的是因为connection一直没有被关闭的原因吗?真希望是,这样就能确认问题了。
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;
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号开始此问题持续追踪,直到找到解决方式。
给所有朋友问声好,祝所有的朋友幸福安康!
主要的问题还是静态变量和程序中的非法关联导致本该被回收的对象一直被关联,无法被GC回收。问题还在持续改进中...