【问题标题】:Hsqldb - a possible prepare statement memory leakHsqldb - 可能的准备语句内存泄漏
【发布时间】: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) 在任何插入之前。

标签: java jdbc hsqldb


【解决方案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:感谢您的补充。我不知道您可以在文件系统中拥有数据库,但在内存表中仍然完整。
猜你喜欢
  • 2015-07-19
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多