-
-
Notifications
You must be signed in to change notification settings - Fork 260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
findStream() / findEach() memory leak #2918
Comments
Hello seg1236 Roland |
@rPraml I use 13.11.0. I don't collect any data. I also tried to run GC explicitly and it didn't help:
|
@serg1236 I tried to reproduce that, so I write a simple test (See below) The test uses a simple entity and creates 10M of them i a DB file. (H2 in memory will not work) But back th the test.
So I don't think there is a memory leak in streaming queries itself, but somewhere else. Can you check the test case, adapt it in your application and maybe provide an example, when a "findEach" query runs in an OOM Roland @Entity
public static class TestModel extends BasicDomain {
@Size(max = 255)
private String someData;
public String getSomeData() {
return someData;
}
public void setSomeData(String someData) {
this.someData = someData;
}
}
@Test
void initDb() {
DatabaseConfig config = new DatabaseConfig();
config.setName("h2-batch");
config.loadFromProperties();
config.setDdlExtra(false);
config.getDataSourceConfig().setUsername("sa");
config.getDataSourceConfig().setPassword("sa");
config.getDataSourceConfig().setUrl("jdbc:h2:file:./testsFile;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE");
config.addClass(TestModel.class);
DatabaseFactory.create(config);
String base = "x".repeat(240);
// 10 mio TestModel - each needs about 1/4 kbytes -> 2,5 GB in total
List<TestModel> batch = new ArrayList<>();
for (int i = 0; i < 10_000_000; i++) {
TestModel m = new TestModel();
m.setSomeData(base + i); // ensure we have not duplicates
batch.add(m);
if (i % 1000 == 0) {
DB.saveAll(batch);
batch.clear();
}
if (i % 100000 == 0) {
System.out.println(i);
}
}
DB.saveAll(batch);
}
@Test
void testOom() {
DatabaseConfig config = new DatabaseConfig();
config.setName("h2-batch");
config.loadFromProperties();
config.setDdlRun(false);
config.getDataSourceConfig().setUsername("sa");
config.getDataSourceConfig().setPassword("sa");
config.getDataSourceConfig().setUrl("jdbc:h2:file:./testsFile;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE");
config.addClass(TestModel.class);
DatabaseFactory.create(config);
AtomicInteger i = new AtomicInteger();
System.out.println("Doing findEach");
DB.find(TestModel.class).select("*").findEach(c -> i.incrementAndGet());
System.out.println("Read " + i + " entries");
i.set(0);
System.out.println("Doing findStream");
DB.find(TestModel.class).select("*").findStream().forEach(c -> i.incrementAndGet());
System.out.println("Read " + i + " entries");
i.set(0);
System.out.println("Doing findIterate");
QueryIterator<TestModel> iter = DB.find(TestModel.class).select("*").findIterate();
while (iter.hasNext()) {
iter.next();
i.incrementAndGet();
}
System.out.println("Read " + i + " entries");
System.out.println("Doing FindList");
List<TestModel> lst = DB.find(TestModel.class).select("*").findList();
System.out.println("Read " + lst.size() + " entries");
} |
@rPraml sorry for the late response. I figured it out. The leak happens only if items have embedded ids.
Even without that storing id as a strong reference may cause OutOfMemory, especially when it's |
@serg1236 thanks for your investigation. I've created the PR #2922 that shoud fix THIS issue. @rbygrave There may be more places, in DefaultServerCache.put we use softreferences as value. In our application, we also often store only the IDs in a List of search results, because the ID is small in comparison to the whole bean. But if the EmbeddedId keeps a reference to it's owner, this is no longer true. My favourite is now #2924 - but this may cause some breaking changes, where I cannot asses the risk. To test I use the above test model and created a model that uses two UUIDs as key. Should I commit the test also? It will only make sense to run the test manually. |
Expected behavior
Query::findStream() and Query::findEach() are supposed to not cache any items in the persistence context.
Actual behavior
Items are being cached in the persistence context causing OutOfMemoryError after some time.
I've done simple tests:
Here is a memory snapshot from the profiler after about 20 sec of execution:
![image](https://user-images.githubusercontent.com/10487569/207874853-c1920dd5-d205-40b3-939f-e16e3e5577f2.png)
P.S. I use Postgresql DB.
The text was updated successfully, but these errors were encountered: