oracle JDBC PreparedStatement 内存释放BUG?

用户fita在使用Oracle 9.2 OCI JDBC驱动访问Oracle 8i数据库时遇到PreparedStatement内存释放问题。若未执行PreparedStatement即关闭,会导致内存泄漏。通过测试发现此问题与Oracle的statement caching特性有关。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.youkuaiyun.com/t/20040623/17/3117011.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值