-
-
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
Change the PersistenceContext default resetLimit for iteration queries to 100 (from 1000) #2407
Conversation
…s to 100 (from 1000)
Hello Rob, thanks for the fix. The memory leak fix seems to be easier than I thought. But why is this done at all? As far as I understand, you put a lot of effort in findIterate (#2021 and so on) so that it periodically starts a new persistence context. What do you generally think if we have only one persistence context, that uses weak references, so that it has not the ability to hold beans in memory. IMHO that would make sense, that the PC holds only the beans in memory, that are strong referenced somewhere else. It would also free up memory if you clear lists (e.g. customer.getOrders().clear() will free all orders in the PC) I made a proof of concept in this branch https://github.com/FOCONIS/ebean/commits/experimental/use-weak-ref I do not know every detail (e.g. if PC is used for prefetch/preload and so on) - I also know, that using references may add additional costs (runtime/memory) - but on the other hand, the change will remove complexity and the PC will cache as many beans as the garbage collection allows. If you think, WeakReferences are the wrong way here, you may take a look at that change FOCONIS@060c385 it will remove code used only in one test. Cheers |
Largely because it means people can then use findEach(), findStream() etc even for small results - choose it for the programming model/style rather than "large resultSet" reasons. In doing so they can get the same behaviour wrt persistence context as if they used findList. That is, people can use findEach(), findStream() without thinking or understanding much and the previous persistence context per top level bean isn't really appropriate/good for that case. I felt we need the default behaviour for small results via findEach/findStream to be just as good as findList. |
Or a specialised persistence context for the iterating queries case that uses weak references. We only get the extra costs of weak references for the iterating queries. |
First, I thought, that can be a good idea, to use the special WeakRef Persistence Context in findIterate/findStream. But there may be the following use cases: try (Transaction txn = DB.beginTransaction) {
list = DB.find(AnyClass.class).query....findList(); // here PC1 is active
resultMap = new HashMap();
DB.find(AnyClass.class).query....findEach( bean -> {
// Here, PC2 (which uses weakReferences) is active, but we must know PC1 as parent
// because 'bean' could be already in 'list'
if (addToResult(bean)) {
resultMap.put(bean.getId(), bean); // Here we pass a bean from the findEach loop to the outer context
}
});
list = DB.find(AnyClass.class).query....findList(); // PC1 is active again, but bean could be in "resultMap" (or should PC2 be active now)
}
I made some quick & dirty performance measurements here: and I think the WeakRefPersistenceContext is about 3 times slower. The measurements are for 100K beans. So DefaultPersistenceContext will ad ~ 130ns per bean get/put and WeakRefPersistenceContext ~ 400ns per bean.
To remove complexity, we could implement a PersistenceContextDelegate: class PersistenceContextDelegate implements PersistenceContext {
private PersistenceContext delegate = new DefaultPersistenceContext();
// delegate methods..
void switchToWeakRef() {
delegate = new WeakRefPersistenceContext(delegate); // copy all content
}
} This would make it much easier to switch from DefaultPersistenceContext to WeakRefPersistenceContext, if a 'forEach' loop will start. (Especially in ReadJson etc) Cheers |
Discard this now. |
FYI @rPraml
Changes the resetLimit from 1000 to 100 for iteration queries (findEach, findIterate, findStream).
Then with
TestPersistenceContext.findWithGcTest()
we see