Home » Eclipse Projects » EclipseLink » Memory leak issue(Long living EntityManager causes memory leak)
| | |
Re: Memory leak issue [message #929586 is a reply to message #929546] |
Mon, 01 October 2012 15:33 |
Chris Delahunt Messages: 1389 Registered: July 2009 |
Senior Member |
|
|
Hello,
How are you registering Entities from #1 in #2 and #3? Are you re-reading them or merging them somehow, and if so, why? How are you detaching them? If you are not using the entities in bean 1 or 2, why do you need them to be managed instances - a read-only hint will makes them detached.
I'm not really sure why you can't call clear. Without clearing the entitymanger between query calls, all entities are being stored in the EntityManager cache. So you are not gaining anything by using pagination since all entities are being brought into the cache by the end anyway. You should be able to use clear at logic points - clear just releases EntityManager's references to managed entities, detaching all entities and allowing GC to clean up the references. It works similar to em.detach except on a larger scale - if using detach on select entities, you could be leaving entities that reference your detached entity in the cache. Since your entityManager is long lived, these entities and their references remain in the cache until it is closed or cleared. Effectively you may be detaching them from EM #2, but leaving entities in the cache that still reference your detached entities, and there are still managed entities representing this data EMs #1+3.
You also mentioned you have 67 RepeatableWriteUnitOfWork. This represents 67 EntityManagers, so either it is under load, or you are keeping alot of EntityManagers and their caches around for a long period without releasing them to be garbage collected.
Best Regards,
Chris
|
|
|
Re: Memory leak issue [message #929645 is a reply to message #929586] |
Mon, 01 October 2012 16:24 |
Jérôme SALLES Messages: 10 Registered: October 2012 |
Junior Member |
|
|
Thank you for your response.
In my heap dump i see 65 RepeatableWriteUnitOfWork and 48 EntityManagerWrapper.
In (1), i load X (you will see People) like this :
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
private void nextPage() {
logger.log(Level.INFO, "L''itérateur de people va changer de page. La prochaine page commencera au People [{0}] et comportera [{1}] objet(s) au maximum", new Object[]{
minBound, getPageSize()
});
try {
this.dynamicList = manager.createQuery(query, People.class).setFirstResult(minBound).setMaxResults(getPageSize()).getResultList();
logger.log(Level.INFO, "La page comporte [{0}] \u00e9l\u00e9ments.", dynamicList.size());
this.dynamicIterator = dynamicList.listIterator();
minBound += dynamicList.size();
} catch (Exception e) {
logger.log(Level.INFO, "Impossible de changer de page : {0}", e.getMessage());
}
}
Even if i let the entity in cache, i see an interest to load my People page per page : the resulting list after invocation of getResultList is known. But i agree with you : it would be better to not store them in the cache. How can i do that ?
In (2), i do something like this :
@Override
public boolean hasNext() {
boolean result = false;
while (!(result = isValidPeople()) && targetEnumeratorEjb.hasNext()) {
if (currentPeople != null) {
manager.detach(currentPeople);
}
currentPeople = targetEnumeratorEjb.next();
}
if (currentWayCom != null) {
manager.detach(currentWayCom);
manager.detach(currentWayCom.getPeople());
}
return result;
}
I recognize that this kind of iteration is a bit strange but this part of the code is complex... As you can see, i detach my people as soon as the test isValidPeople is done. This test doesn't write in people : the test could be done on a detached entity.
In (3) i edit datas like this (there is another method that work in the same way) :
@Override
public void invalidate(Mailing mailing, Recipient recipient) {
WayComAdapter adapter = (WayComAdapter) recipient;
if (adapter != null && adapter.getWayCom() != null) {
EntityManager manager = getManager();
WayCom wayCom = manager.merge(adapter.getWayCom());
wayCom.setStatus(WayComStatus.INVALID);
wayCom.setEnabled(false);
adapter.setWayCom(wayCom);
manager.flush();
manager.detach(wayCom.getPeople());
manager.detach(wayCom);
manager.getTransaction().commit();
manager.close();
}
}
private EntityManager getManager() {
try {
EntityManager result = factory.createEntityManager();
result.getTransaction().begin();
return result;
} catch (Exception ex) {
Logger.getLogger(RoutingHandlerBean.class.getName()).log(Level.SEVERE, "Cannot start transaction : {0}", ex.getMessage());
return null;
}
}
I merge the entity with the current entitymanager build in the method getManager.
I think that you are right : i should use clear on (1) and (2). For (3), it's not necessary as i call close on my EntityManager. That's right ?
Thank you !
Mon CV d'architecte logiciel Java EE
|
|
| | | | | |
Re: Memory leak issue [message #933010 is a reply to message #931925] |
Thu, 04 October 2012 16:47 |
Chris Delahunt Messages: 1389 Registered: July 2009 |
Senior Member |
|
|
The screenshot and the code lead me to believe this is the same as the intial issue. Your EntityManagers are long lived, and you are only removing the single entity from the cache that was read in - but you haven't shown any of the relationships in your entities. When building an object, these too can get brought in depending on the eager/fetch settings. Since you are only ever removing the owning entity and never clearing/closing the EM- the related entities will remain in the cache for the life of the app.
There is no way to tell from what you've provided for sure how the People entity got in the cache, but I suspect StartEntity or some other object has references to People. If they are Eager, then the referenced People entities will be immediately be managed and placed in the cache. If they are lazy, they will be put in the cache if and when the relationship is accessed. One thing to note about EclipseLink behavior is that EclipseLink allows traversing lazy relationships on detached entities as long as the context is still available. This might be a problem for your cache since you never close the EntityManager, so it is always available. You also mentioned you are not explicietely loading People from this EM so I guess you never explicietely remove it from the cache either.
You will need to look over your app design and either close and reobtain EntityManagers at points, clear them, or a combination of both. Reusing the same EntityManager without clearing allows it to build up references.
Please also note that in the code above, manager.contains(event) should always return true, so you might want to just call clear at this point without the check. I'd recommend refactoring your methods to keep the EntityManager local to the method, and initially call a getEntityManager() method that can create a new one or provide the existing one if in a transaction.
Best Regards,
Chris
|
|
|
Re: Memory leak issue [message #933611 is a reply to message #933010] |
Fri, 05 October 2012 07:05 |
Jérôme SALLES Messages: 10 Registered: October 2012 |
Junior Member |
|
|
Chris, Thank you for your reply.
I have effectively one people in my StartEvent. This people is not read from it and so i think this people is never cached, but i could be wrong...
Furthermore, People i see in the screenshot have no relation with the startevent. Those People are load from a query by (3), page per page, and the entitymanager is cleared after each page. The code look like this after your suggestion :
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
private void nextPage() {
logger.log(Level.INFO, "L''itérateur de people va changer de page. La prochaine page commencera au People [{0}] et comportera [{1}] objet(s) au maximum", new Object[]{
minBound, getPageSize()
});
try {
this.dynamicList = manager.createQuery(query, People.class).setFirstResult(minBound).setMaxResults(getPageSize()).getResultList();
logger.log(Level.INFO, "La page comporte [{0}] \u00e9l\u00e9ments.", dynamicList.size());
this.dynamicIterator = dynamicList.listIterator();
//http://www.eclipse.org/forums/index.php/mv/msg/389907/929761/#msg_929761
manager.clear();
minBound += dynamicList.size();
} catch (Exception e) {
logger.log(Level.INFO, "Impossible de changer de page : {0}", e.getMessage());
}
}
For me, RepeatableWriteUnitOfWork can be shared between different EntityManager (that's why StartEvent and People are in the same one). The only problem is : why manager.clear() is not applied in the code above ?
Mon CV d'architecte logiciel Java EE
|
|
| | | | |
Re: Memory leak issue [message #1497543 is a reply to message #929435] |
Wed, 03 December 2014 22:15 |
Nuno Godinho de Matos Messages: 34 Registered: September 2012 |
Member |
|
|
Hi Chris,
On your analysis of the initial thread you Imply:
67 Repeatble Write units of work imply 67 entity managers.
Closing entity manager detaches and makes all entities loaded through garbae collectable.
Well, I've created a simple Sample project which I can later reference if you wish.
On it I created a simple JSf page with a backing bean.
This backing bean has different attributes that I can populate through queries by clicking some buttons on the interface.
The attributes of the form:
(a) attr1 - output of query fetched through pure injected persistence context
(b) attr2 - output of query fetched by intermediation of local Enterprise Java Bean
(c) attr3 - output of the query fetched by a Remote enterprise jave bean.
After clicking on three buttons and geting the three attributes populated, I run a heap dump, and what I see is the following.
Attribute 3 contains a vector containing two leightweight entities with very little retained size.
Bout attribute 1 and 2 contain a vector with the query results where each entity is much fatter in terms of retained size.
If I query the heap dump for EntityManagerImpl instances, there are 0.
The container seems to have done its job of managing the Entity Managers it injected either onto the Bean itsel,f the local facade or the remote facade.
These entity managers have been garbage collected.
However, in terms o repeatble write unit of work, I have two.
One of these first level caches is Bound the entities in Attribute 1 and the other two entites in attribute 2.
Meaning, returning a datbase entity using a local facade gives you an attached enetity that will hang on to the cache from the entity manager that spawned it. Even if, apperenlty, the contianer would have closed the entity manager.
The replationship I see on the heap Dump is of the Form
Queried Entitiy -> _persistence_listener : AttributeChangeListneer -> uow: RepeatbleWriteUnitOfWork.
It seems like there are no long lived entity managers in this case, but ther eare long lived caches despite of it.
|
|
|
Goto Forum:
Current Time: Wed Dec 11 13:52:01 GMT 2024
Powered by FUDForum. Page generated in 0.28142 seconds
|