Java 为什么HSQLDB在多次插入后会产生OutOfMemoryError,即使数据库是空的?
我们正在使用HSQLDB进行一系列JUnit集成测试。对于一个特定的测试,我需要加载一组数据来验证我们在数据库上运行的一些算法。套件中的每个测试将插入一个大批量,测试算法,然后删除所有记录。不幸的是,HSQLDB最终会抛出OutOfMemoryError,即使每次都会清除所有记录,并且在任何给定时间数据库中的最大记录数都不会改变 这里有一个简单的JUnit测试来重现这一点。正如您所看到的,它只是插入然后删除一堆行。导致错误的删除之后,HSQLDB在内存中保留了什么?为了能够无限期地运行insert deletes(或者至少能够执行所有测试),我可以更改什么Java 为什么HSQLDB在多次插入后会产生OutOfMemoryError,即使数据库是空的?,java,hsqldb,Java,Hsqldb,我们正在使用HSQLDB进行一系列JUnit集成测试。对于一个特定的测试,我需要加载一组数据来验证我们在数据库上运行的一些算法。套件中的每个测试将插入一个大批量,测试算法,然后删除所有记录。不幸的是,HSQLDB最终会抛出OutOfMemoryError,即使每次都会清除所有记录,并且在任何给定时间数据库中的最大记录数都不会改变 这里有一个简单的JUnit测试来重现这一点。正如您所看到的,它只是插入然后删除一堆行。导致错误的删除之后,HSQLDB在内存中保留了什么?为了能够无限期地运行inser
注意:我知道我可以增加单元测试的内存限制,或者在这两者之间关闭数据库,但是在有人向我提供合理的解释之前,我觉得我应该能够预期清空内存中的HSQLDB实际上也应该释放它所使用的内存。这种现象在2.5.1之前的版本中存在 这不是一个bug。在没有文件的
mem:
(仅限内存)数据库中,当列类型为CLOB(与VARCHAR相反)时,字符串对象存储在单独的内存LOB存储中,删除行时不会清除该存储。您需要不时执行检查点以清除LOB存储。在每次运行结束时添加executeSQL(“检查点”)
您可以将该列声明为LONGVARCHAR或任何足够大的VARCHAR(n),以避免使用CHECKPOINT语句
此问题不会出现在文件:
数据库中,这些数据库使用文件存储LOB,即使该表是内存表。在这些数据库中,检查点释放.lobs
文件中已删除块占用的空间。然后,这些空间将被重新用于新的LOB
在最新版本2.5.1中,当从
mem:
数据库中删除LOB时,也会执行自动检查点。在这里,hsqldb.log_size
设置适用于触发检查点的已删除lob数据总量(MB)。早于2.5.1的版本中存在这种现象
这不是一个bug。在没有文件的mem:
(仅限内存)数据库中,当列类型为CLOB(与VARCHAR相反)时,字符串对象存储在单独的内存LOB存储中,删除行时不会清除该存储。您需要不时执行检查点以清除LOB存储。在每次运行结束时添加executeSQL(“检查点”)
您可以将该列声明为LONGVARCHAR或任何足够大的VARCHAR(n),以避免使用CHECKPOINT语句
此问题不会出现在文件:
数据库中,这些数据库使用文件存储LOB,即使该表是内存表。在这些数据库中,检查点释放.lobs
文件中已删除块占用的空间。然后,这些空间将被重新用于新的LOB
在最新版本2.5.1中,当从
mem:
数据库中删除LOB时,也会执行自动检查点。这里,hsqldb.log_size
设置适用于触发检查点的已删除lob数据总量(MB)。“这不是一个bug。”-这是有争议的:-)。@Stephen,您的评论提醒您更新答案!“这不是一个bug。”-这是有争议的:-)@Stephen,你的评论提醒我们更新答案!
package mypackage;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Verifying HSQLDB OutOfMemoryError
*
* @author Ricardo van den Broek
*/
public class HsqlDbTest {
@Test
public void test() throws Exception {
executeSql("CREATE TABLE MY_TABLE (MY_COLUMN CLOB)");
String str = "TESTTESTTESTTESTTESTTESTTESTTEST";
String x = String.format("INSERT INTO MY_TABLE VALUES('%S')", str);
for (int i=0;i<1000;i++){
System.out.println("Starting batch: "+i);
for (int j=0; j<10000; j++) {
executeSql(x);
}
System.out.println("Inserted: "+getCount());
executeSql("DELETE FROM MY_TABLE");
System.out.println("After delete: "+getCount());
}
}
private void executeSql(String sql) throws SQLException {
Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:a");
PreparedStatement ps = c.prepareStatement(sql);
ps.executeUpdate();
ps.close();
c.close();
}
private long getCount() throws Exception {
Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:a");
PreparedStatement ps = c.prepareStatement("SELECT COUNT(*) FROM MY_TABLE");
ResultSet resultSet = ps.executeQuery();
if (resultSet.next()) {
long count = resultSet.getLong(1);
ps.close();
c.close();
return count;
}
throw new Exception("Should not happen");
}
}
Starting batch: 0
Inserted: 10000
After delete: 0
Starting batch: 1
# ...
# Omitting some repetition
# ...
Inserted: 10000
After delete: 0
Starting batch: 10
java.sql.SQLException: java.lang.OutOfMemoryError: Java heap space