xiejin2008
xiejin2008
2008-12-22 18:17

最近我公司的网站,服务器时间长了.就会报内存溢出.找不到原因

已采纳

最近我公司的网站,服务器时间长了,访问量变大.就会报内存溢出.找不到原因.
    在网上搜索了很多资料.关于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页面"
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

6条回答

  • aidiyuxin aidiyuxin 13年前

    [quote] 1. 如果我一个jsp页面,要调用很多dao类里的方法,为什么不把Connection 在页面获取呢,可以直接传到Dao类.这样不比在Dao类中的每个方法里面重新获取连接不更好吗? [/quote]
    如果你每次都在页面上都创建connection,之后又去析构他,但是gc的机制决定了这个connection不会被马上回收,这样时间一长连接就被占满了

    [quote] 2.如果按照最上面的那个帖子的说法,采用单例模式的类里面如果有其他类的引用或对象,这些对象是不是永远不会销毁呢?这是内存泄露吗?[/quote]
    如果这个对象被用着,就不叫内存泄露

    ps:不知道你这个工程反射或者动态代理类用的多不多,如果多的话,可能是你启动tomcat时候没有配置jvm的perm的大小;但是每个页面都去创建connection真的很让人崩溃啊。。。这样效率很低下的,推荐楼主还是使用orm这样的东西吧,要不然要处理的事太多了

    点赞 评论 复制链接分享
  • iteye_19016 iteye_19016 13年前

    [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]

    点赞 评论 复制链接分享
  • iteye_19016 iteye_19016 13年前

    [code="java"]
    //finally{} 写的是关闭 session的代码 不是直接赋null
    //赋值为null 对象不会立刻被销毁 什么时候销毁由jvm决定
    4.在finally{} 将对象置为null ,是不是真的内存回收了呢?
    [/code]

    点赞 评论 复制链接分享
  • aidiyuxin aidiyuxin 13年前

    晕啊。。。
    jsp页面connection满天飞

    这样肯定是不行的
    我猜你这个页面是专用的数据库连页面对吧?
    之后每个页面都include这个页面?

    如果是的话肯定不行
    每个页面都会从新初始化数据库连接,这样tomcat铁定挂

    点赞 评论 复制链接分享
  • aidiyuxin aidiyuxin 13年前

    帅哥,不知您是否用到数据库连接池呢?

    点赞 评论 复制链接分享
  • lggegegmail lggegegmail 13年前

    你的这个类感觉上没问题.

    [quote]都是在jsp或者servlet中创建连接对象[/quote]

    这个connection 是写在servlet的init里面的?
    还是写在doGet, doPost 里面的呢?

    问题比较可能发生在对Connection的处理上

    点赞 评论 复制链接分享