oracle JDBC PreparedStatement 内存释放BUG?

oracle JDBC PreparedStatement 内存释放BUG?
楼主fita(天外飞仙)2004-06-23 17:28:27 在 Java / J2SE / 基础类 提问
我用oracle   9.2   的OCI   JDBC驱动以及oracle9.2客户端,访问   oracle   8i   数据库服务器,发现一个问题:  
   
  当用   conn.prepareStatement语句prepare好一个PreparedStatement后,如果执行过execute,再调用close,则相应的内存就会被释放,如果没有调用PreparedStatement的execute语句,就调用close把它关掉的话,这个语句占用的内存将不会释放,导致内存泄漏。  
  大家碰到过这个问题吗?这是Oracle的BUG吗?有没有好的解决办法?  
   
   
  下面的代码不会产生内存泄漏  
  Connection   conn;  
  ……    
  PreparedStatement   stat   =   null;  
  ResultSet   rs   =   null;  
  try  
  {  
        stat   =   conn.preparedStatement("SELECT   *   FROM   TABLE1   WHERE   F1=?");  
        stat.setString(1,"1");  
        rs   =   stat.executeQuery();  
        ……  
  }  
  catch   (SQLException   e)  
  {  
  }  
  finally  
  {  
        if   (rs!=null)    
        {  
              try  
              {  
              rs.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              rs   =   null;  
          }  
        if   (stat!=null)  
        {  
              try  
              {  
              stat.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              stat   =   null;  
        }  
  }  
   
   
  而下面的代码会有内存泄漏,泄漏的内存调用   GC   也释放不掉  
  Connection   conn;  
  ……    
  PreparedStatement   stat   =   null;  
  ResultSet   rs   =   null;  
  try  
  {  
        stat   =   conn.preparedStatement("SELECT   *   FROM   TABLE1   WHERE   F1=?");  
        //不执行任何操作  
  }  
  catch   (SQLException   e)  
  {  
  }  
  finally  
  {  
        if   (rs!=null)    
        {  
              try  
              {  
              rs.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              rs   =   null;  
          }  
        if   (stat!=null)  
        {  
              try  
              {  
              stat.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              stat   =   null;  
        }  
  }  
 
问题点数:100、回复次数:13
Top


1 楼pastelife(Samuel)回复于 2004-06-23 19:34:37 得分 10concerning..
Top

2 楼ldianfeng(教授)回复于 2004-06-23 20:27:21 得分 10是吗?不可能吧!如果是你作一个代理,判断。然后把他关了。
Top

3 楼fita(天外飞仙)回复于 2004-06-24 09:52:09 得分 0 我也觉得不可能,但实际测试的情况的确如此,用一个循环测试可以看到第二种情况下使用内存快速地增长。   大家也来测试一下,看看你们那儿是否也是如此?  
  当然,如果我知道这个PreparedStatement不会执行,可以不去准备这个语句,但是实际情况中有是很难判断,比如说执行中发生异常。  
  不知道有谁知道对于一个PreparedStatement怎么才能完整地释放呢,不管它有没有执行过?  
 
Top

4 楼ningIII(小宁)回复于 2004-06-24 09:59:09 得分 30直接关闭连接即可~
Top

5 楼fita(天外飞仙)回复于 2004-06-24 10:19:36 得分 0 我的连接是缓存下来的,以后直接重用,不希望每次都关闭掉。还有什么方法?
Top

6 楼fita(天外飞仙)回复于 2004-06-25 11:50:23 得分 0 up
Top

7 楼Minsc79(天使之翼)回复于 2004-06-25 11:56:00 得分 0 gz
Top

8 楼bin1982(兵)回复于 2004-06-25 12:31:54 得分 0 up
Top

9 楼dugang106(冷风细雨)回复于 2004-06-25 12:54:33 得分 20楼主的连接使用率还真高!  
  好象让人难以理解  
  为什么不用连接池?假设用了连接池,还缓存connection干吗?  
  你这本身没有释放内存就是因为connection没有关闭的原因。  
  不是oracle的bug,而是你们架构的问题。
Top

10 楼fita(天外飞仙)回复于 2004-06-25 17:16:51 得分 0 我用连接池测试,还是一样  
  Connection   是从   poolconnection   获取出来的逻辑连接,connection我是关掉了的,而实际的物理连接是不会关闭的。  
  下面的代码我也测试过,内存也没有释放,这个总不是我架构的问题了吧  
   
  PooledConnection   pooledConnection;  
  ……  
  Connection   conn   =   null;  
  PreparedStatement   stat   =   null;  
  ResultSet   rs   =   null;  
  try  
  {  
        conn   =   pooledConnection.getConnection();  
        stat   =   conn.preparedStatement("SELECT   *   FROM   TABLE1   WHERE   F1=?");  
        //不执行任何操作  
  }  
  catch   (SQLException   e)  
  {  
  }  
  finally  
  {  
        if   (rs!=null)    
        {  
              try  
              {  
              rs.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              rs   =   null;  
          }  
        if   (stat!=null)  
        {  
              try  
              {  
              stat.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              stat   =   null;  
        }  
        if   (conn!=null)  
        {  
              try  
              {  
              conn.close();  
              }  
              catch   (SQLException   e1)    
              {  
              }  
              conn   =   null;  
        }  
  }  
 
Top

11 楼yujinping(FrameWork)回复于 2004-06-25 17:56:10 得分 30是Connection   没有关闭的原因
Top

12 楼fita(天外飞仙)回复于 2004-06-25 19:10:46 得分 0 终于发现问题了,是因为我的代码使用了oracle的statement   cacheing特性的原因,如果不使用则没有问题。哎,本来很好的一个特性,却因为有这个问题而不能用了   :-(  
   
  测试代码:  
   
      public   void   test()  
      {  
          DecimalFormat   m_nf   =   new   DecimalFormat("###,###");  
          try  
          {  
              OracleConnectionPoolDataSource   ods   =   new   OracleConnectionPoolDataSource();  
              ods.setURL("jdbc:oracle:oci:@db_67");  
               
              OraclePooledConnection   pc   =   (OraclePooledConnection)ods.getPooledConnection("system","manager");  
              pc.setStatementCacheSize(100);   //把这一句取掉,就不会有内存增长了  
              long   lLastTime   =   0;  
              while   (true)  
              {  
                  Connection   conn   =   null;  
                  ResultSet   rs   =   null;  
                  PreparedStatement   stat   =   null;  
                  try  
                  {  
                      conn   =   pc.getConnection();  
                      stat   =   conn.prepareStatement("SELECT   sysdate   from   dual");  
  //   如果加上了下面的语句,那么前面设置了statementcache也不会有内存增长  
  //                     rs   =   stat.executeQuery();  
  //                     while   (rs.next())  
  //                     {  
  //                         String   value   =   rs.getString(1);  
  //                     }  
                  }  
                  catch   (SQLException   ex1)  
                  {  
                      ex1.printStackTrace();  
                  }  
                  finally  
                  {  
                          try  
                          {  
                          if   (rs!=null)  
                          {  
                              rs.close();  
                              rs=null;  
                          }  
                          if   (stat!=null)  
                          {  
                              stat.close   ();  
                              stat=null;  
                          }  
                          if   (conn!=null)  
                          {  
                              conn.close();  
                              conn=null;  
                          }  
                      }  
                      catch   (SQLException   ex2)  
                      {  
                          ex2.printStackTrace();  
                      }  
                  }  
                  long   lNow   =   System.currentTimeMillis();  
                  if   (lNow-lLastTime>5000)  
                  {  
                      System.gc();  
                      long   lTotalMemory,lFreeMemory;  
                      lTotalMemory   =   java.lang.Runtime.getRuntime().totalMemory();  
                      lFreeMemory   =   java.lang.Runtime.getRuntime().freeMemory();  
                      System.out.println("GC后内存,总数="+m_nf.format(lTotalMemory)+  
                                                            ",空闲="+m_nf.format(lFreeMemory)+  
                                                            ",使用="+m_nf.format(lTotalMemory-lFreeMemory));  
                      lLastTime   =   lNow;  
                  }  
                  try  
                  {  
                      Thread.sleep(1);  
                  }  
                  catch   (InterruptedException   ex3)  
                  {  
                      break;  
                  }  
              }  
   
          }  
          catch   (SQLException   e)  
          {  
              e.printStackTrace();  
          }  
           
      }  
 
Top

13 楼fita(天外飞仙)回复于 2004-06-25 19:14:47 得分 0 大家不要简单关闭Connection去解决这个问题,在一个高性能程序中,决不应该频繁地关闭物理连接。认真分析,找到真正的原因才是解决之道。衷心希望真正的高手能提供好的解决办法。


转载地址:http://topic.csdn.net/t/20040623/17/3117011.html

你可能感兴趣的:(oracle,.net,jdbc,J2SE,UP)