最近我公司的网站,服务器时间长了,访问量变大.就会报内存溢出.找不到原因.
在网上搜索了很多资料.关于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 ,是不是真的内存回收了呢?
[quote] 1. 如果我一个jsp页面,要调用很多dao类里的方法,为什么不把Connection 在页面获取呢,可以直接传到Dao类.这样不比在Dao类中的每个方法里面重新获取连接不更好吗? [/quote]
如果你每次都在页面上都创建connection,之后又去析构他,但是gc的机制决定了这个connection不会被马上回收,这样时间一长连接就被占满了
[quote] 2.如果按照最上面的那个帖子的说法,采用单例模式的类里面如果有其他类的引用或对象,这些对象是不是永远不会销毁呢?这是内存泄露吗?[/quote]
如果这个对象被用着,就不叫内存泄露
ps:不知道你这个工程反射或者动态代理类用的多不多,如果多的话,可能是你启动tomcat时候没有配置jvm的perm的大小;但是每个页面都去创建connection真的很让人崩溃啊。。。这样效率很低下的,推荐楼主还是使用orm这样的东西吧,要不然要处理的事太多了
你的这个类感觉上没问题.
[quote]都是在jsp或者servlet中创建连接对象[/quote]
这个connection 是写在servlet的init里面的?
还是写在doGet, doPost 里面的呢?
问题比较可能发生在对Connection的处理上
帅哥,不知您是否用到数据库连接池呢?
晕啊。。。
jsp页面connection满天飞
这样肯定是不行的
我猜你这个页面是专用的数据库连页面对吧?
之后每个页面都include这个页面?
如果是的话肯定不行
每个页面都会从新初始化数据库连接,这样tomcat铁定挂
[code="java"]
//finally{} 写的是关闭 session的代码 不是直接赋null
//赋值为null 对象不会立刻被销毁 什么时候销毁由jvm决定
4.在finally{} 将对象置为null ,是不是真的内存回收了呢?
[/code]
[code="java"]//B类采用单例模式
class B{
private A a;
private static B instance=new B();
//单例模式 构造方法应该为 private
public B(){}
public static B getInstance(){
return instance;
}
public void setA(A a){
this.a=a;
}
//getter...
} [/code]