Hsqldb - 可能的准备语句内存泄漏

Posted

技术标签:

【中文标题】Hsqldb - 可能的准备语句内存泄漏【英文标题】:Hsqldb - a possible prepare statement memory leak 【发布时间】:2014-03-25 23:56:52 【问题描述】:

我正在使用 hsqldb 版本 2.3.1 或 2.3.2(发现两者都有问题)。

我有一些代码,我在其中执行了大量对数据库的插入操作,并且我可能会清理所有资源 - 但我注意到在语句上调用 execute 会导致内存永远不会消失 - 即使我关闭了准备好的语句,连接等......

这是您可以在您的机器上运行并验证的代码(在 java 默认堆大小上运行,OutOfMemory 应该会在 5 分钟内出现):

Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:a");
PreparedStatement ps = c.prepareStatement("set database sql syntax ora true");
ps.execute();
ps.close();

ps = c.prepareStatement("create table t (x varchar2(1000 char))");
ps.execute();
ps.close();
c.close();
String str = "abcdefghijklmnopqrstuvwxyz";
str = str + str + str + str + str; //just a long string to rapid the outcome
String x = String.format("insert into t values('%s')",str);
for(int i=0;i<1000*1000*1000;i++)
   c = DriverManager.getConnection("jdbc:hsqldb:mem:a");
   ps = c.prepareStatement(x);
   ps.executeUpdate(); //if I remove this line, there is no memory leak
   ps.clearParameters();//I really try to clean every possible thing
   ps.clearWarnings();//really try
   ps.cancel();//cancel it even
   ps.close();//close it of course
   ps = null;//nullify to hint the GC
   c.rollback(); //Rollback so that memory isn't even used inside the hsqldb
   c.close();//close the connection even

   if(i%100000 == 0)//Every once in a while a report about heap condition
 System.gc();//perform gc
     System.out.println(Runtime.getRuntime().freeMemory()/1024/1024);//in MB
   
 

如果您运行代码,定期打印将打印可用的可用内存 - 将逐渐减少,直到 OutOfMemory。

如您所见,我尝试关闭、回滚、取消等 - 似乎没有任何效果。

使用 JvisualVM 似乎大部分内存是 byte[]。

如果我是对的并且这是一个错误,我正在寻找一种解决方法。有什么建议么?我做错了吗?

谢谢

【问题讨论】:

您的回滚尝试不起作用,因为连接处于自动提交模式并且 INSERT 已自动提交。它需要 c.setAutoCommit(false) 在任何插入之前。 【参考方案1】:

在此处阅读http://hsqldb.org/doc/guide/dbproperties-chapt.html 关于关机的信息。

如果未指定,即使您关闭了与内存数据库中的 HSQL 的最后一个连接,数据库本身也不会被破坏并保留在内存中。您在此数据库中添加每个插入新行,并且它会增长。

如果数据库不保留,那么您将永远无法插入,因为在创建数据库和表 t 之后,您关闭连接,然后重新打开后,表应该消失了,不应该。

如果你第一次打开它,你可以在最后一个连接关闭后强制关闭数据库:

Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:a;shutdown=true");

但是现在你不能再插入了,因为在新的getConnection 之后你的表已经不存在了。

关闭数据库并释放所有内存的另一种可能性是 HSQL 的 SQL 命令SHUTDOWN

c.createStatement().execute("SHUTDOWN");

如果您要处理更大的数据,您的第一个选择应该是在文件系统中创建一个带有基于磁盘的 CACHED 表的 HSQL 数据库。那么它的内存占用就不会像它在内存中那样随着数据的增长而增长。

【讨论】:

@fredt:感谢您的补充。我不知道您可以在文件系统中拥有数据库,但在内存表中仍然完整。

以上是关于Hsqldb - 可能的准备语句内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

堆中的 DLL 内存泄漏

C ++中的内存泄漏示例(通过使用异常)[重复]

如何用VS工具检测内存泄露

Java内存泄漏的几种可能

使用导致内存泄漏的音频片段

Release编译模式下,事件是否会引起内存泄漏问题初步研究