最近我公司的网站,服务器时间长了,访问量变大.就会报内存溢出.找不到原因.
在网上搜索了很多资料.关于java内存泄露方面的东西.我怀疑是我们java类中用了单例模式惹的祸.但还不敢确定. 我对单例模式,也只懂得一二.希望各位网友.可以讨论讨论.我希望能尽快找到解决方法.
下面是我在网上搜索的一个关于单例模式,有内存泄露的帖子:http://java.csdn.net/page/bf856ae4-ef93-4355-b43d-3735cba92279
大概意思:
单例模式。不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露,考虑下面的例子: class A{ public A(){ B.getInstance().setA(this); } .... } //B类采用单例模式 class B{ private A a; private static B instance=new B(); public B(){} public static B getInstance(){ return instance; } public void setA(A a){ this.a=a; } //getter... } 显然B采用singleton模式,他持有一个A对象的引用,而这个A类的对象将不能被回收。想象下如果A是个比较大的对象或者集合类型会发生什么情况。
我再贴出我项目中的java代码(提取出来的).供大家分析.
import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.log4j.Logger; import com.viewbean.Mms; public class MyDBTest { Statement stmt= null; ResultSet res = null; private static final Logger logger = Logger.getLogger(Mms.class); private static final MyDBTest instance = new MyDBTest(); public static MyDBTest getInstance() { return instance; } private MyDBTest() { } /** * * @param con * @param a * @param b * @param c * @param i 调用sql语句的序号. * @return */ public String[][] getOs(java.sql.Connection con,String a,String b ,String c,int i ){ logger.debug("获取某某..."); String[] sql={ // 0. "select a from mysql where a ='"+b+"'", //1. "select a from mysql where b ='"+b+"'", //2. "select a from mysql where c ='"+c+"'" // sql语句都是 用 + 号拼起来的. }; try { stmt = con.createStatement(); res= stmt.executeQuery(sql[i]); //................ //对res进行其他操作.返回一个String[][]二维数组 } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(stmt!=null) stmt.close(); if(res!=null) res.close(); //con 连接对象.在jsp中被关闭. } catch (SQLException e) { e.printStackTrace(); } sql=null; } return null;//实际返回二维数组.现在模式返回null; } public boolean deleteGif(java.sql.Connection conn,String aa) { logger.debug("删除某某..."); return false; } public void insertmms(java.sql.Connection con,String linkid,String id){ logger.debug("添加某某..."); } }
由于是一个网站项目,没有很复杂的框架.应用了简单的jsp+javabean模式开发.
所以都是在jsp或者servlet中创建连接对象.然后调用这些java类.并且这些类都应用了单利模式.
其他的jsp直接调用getInstance()方法.然后调用其中的方法.执行sql操作.并且连接对象是在jsp中try{}catch{}finally{}
finally{}里中关闭里.所有jsp中的对象和String,String[][]都设置为null.
现在我的疑问就是:1.向我这种代码.javabean设置为单例模式,会不会有内存泄露的结果.
2.我那是用了logger4j的对象,始终没有清空他.他应不应该进行logger =null 操作.
3.还有拼sql 语句.有没有跟好的方法.
4.在finally{} 将对象置为null ,是不是真的内存回收了呢?
问题补充:
我们项目应用了 数据库连接池.如果数据库连接池没有链接到,就用直连的.
我们获取Connection大多数在jsp中/比如:
<%
// 查询某用户的未读消息几条
Connection conn = null;
String[][] strNewCount=null;
try{
conn = DBAccess.getPooledConnection();
strNewCount=MessageManageDao.getInstance().pageQueryMessage(conn,userId,-1,-1,0,2);
if(strNewCount!=null&&strNewCount.length>0){
newCounts= Integer.parseInt(strNewCount[0][0]);
}
}catch(Exception e){
e.printStackTrace();}
finally{
DBAccess.closeConnection(conn);
}
%>
在servlet里面的连接.都是写在doGet() 或 doPost() 方法里面的.
希望大家继续关注....
问题补充:
问题再次补充并进行我的分析:
回答,墓里活人:
我那个页面不是专门用来获得连接.也没有其他页面包含他,我说的是,我用很多 jsp页面,这些页面如果要获取数据,进行操作.都是直接<% %> 在这个里面获取连接,并调用方法.获得String[][]返回或无返回值.
获得的连接.在页面末尾的finally{} 块中关闭啦.
单例.那个B类的构造方法,没有写那个private,我是copy别人的帖子中
的.我猜是手误.
我的疑问:
1. 如果我一个jsp页面,要调用很多dao类里的方法,为什么不把Connection 在页面获取呢,可以直接传到Dao类.这样不比在Dao类中的每个方法里面重新获取连接不更好吗?
2.如果按照最上面的那个帖子的说法,采用单例模式的类里面如果有其他类的引用或对象,这些对象是不是永远不会销毁呢?这是内存泄露吗?
问题补充:
错别字更正:"我用很多 jsp页面" --->>> "我有很多jsp页面"