oracle JDBC PreparedStatement 内存释放BUG?

fita 2004-06-23 05:28:27
我用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;
}
}
...全文
548 13 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
dugang106 2004-06-25
  • 打赏
  • 举报
回复
楼主的连接使用率还真高!
好象让人难以理解
为什么不用连接池?假设用了连接池,还缓存connection干吗?
你这本身没有释放内存就是因为connection没有关闭的原因。
不是oracle的bug,而是你们架构的问题。
bin1982 2004-06-25
  • 打赏
  • 举报
回复
up
Minsc79 2004-06-25
  • 打赏
  • 举报
回复
gz
fita 2004-06-25
  • 打赏
  • 举报
回复
up
fita 2004-06-25
  • 打赏
  • 举报
回复
大家不要简单关闭Connection去解决这个问题,在一个高性能程序中,决不应该频繁地关闭物理连接。认真分析,找到真正的原因才是解决之道。衷心希望真正的高手能提供好的解决办法。
fita 2004-06-25
  • 打赏
  • 举报
回复
终于发现问题了,是因为我的代码使用了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();
}

}
yujinping 2004-06-25
  • 打赏
  • 举报
回复
是Connection 没有关闭的原因
fita 2004-06-25
  • 打赏
  • 举报
回复
我用连接池测试,还是一样
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;
}
}
fita 2004-06-24
  • 打赏
  • 举报
回复
我的连接是缓存下来的,以后直接重用,不希望每次都关闭掉。还有什么方法?
ningIII 2004-06-24
  • 打赏
  • 举报
回复
直接关闭连接即可~
fita 2004-06-24
  • 打赏
  • 举报
回复
我也觉得不可能,但实际测试的情况的确如此,用一个循环测试可以看到第二种情况下使用内存快速地增长。 大家也来测试一下,看看你们那儿是否也是如此?
当然,如果我知道这个PreparedStatement不会执行,可以不去准备这个语句,但是实际情况中有是很难判断,比如说执行中发生异常。
不知道有谁知道对于一个PreparedStatement怎么才能完整地释放呢,不管它有没有执行过?
林巅峰 2004-06-23
  • 打赏
  • 举报
回复
是吗?不可能吧!如果是你作一个代理,判断。然后把他关了。
pastelife 2004-06-23
  • 打赏
  • 举报
回复
concerning..

62,635

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧