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 - 可能的准备语句内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章