views:

1061

answers:

4

I have a slow memory leak in my Java application. I was wondering if this could be caused by not always closing the Entitymanager when used. However using myeclipse to generate DB code, I'm getting methods like this:

public Meit update(Meit entity) {
 logger.info("updating Meit instance");
 try {
  Meit result = getEntityManager().merge(entity);
  logger.info("update successful");
  return result;
 } catch (RuntimeException re) {
  logger.error("update failed");
  throw re;
 }
}

Which never close the EntityManager. Considering this is generated code, I'm wondering who's right, me or the IDE.

+1  A: 

Entity managers should generally have the same lifecycle as the application and not be created or destroyed on a per-request basis.

Your "memory leak" may be nothing more than the caching JPA is doing. You don't say which JPA provider you use but I know from experience that EclipseLink by default does extensive caching (which is part of the alleged benefits of JPA and ORM in general).

How do you know you have a memory leak?

cletus
I know I have a memory leak because the application crashes every few weeks and gives out of memory errors. It's a web app. I am using eclipselink. I thought the EM's should be closed based on:http://stackoverflow.com/questions/220374/do-i-have-to-close-every-entitymanager
Greg
Are you creating an EMF by hand? In a Web app you should be injecting it like the accepted answer says in which case you shouldn't be creating or closing it by hand. Is Spring in this picture?
cletus
I am using Tomcat, so it cannot be injected as there are no EJBs. I am using an EntityManagerFactory to create the EM. I am guessing that somehow once the session expires, these are not being cleaned up.
Greg
Ah I'm used to Glassfish. I see from http://www.oracle.com/technology/products/ias/toplink/jpa/tutorials/jsf-jpa-tutorial.html you're doing what's suggested. Have you seen http://wiki.eclipse.org/EclipseLink/Examples/JPA/Tomcat_Web_Tutorial#Tomcat_configuration_Changes?
cletus
A: 

Check whether it's really a leak

if so get the Eclipse Memory Analyzer and analyze it.

The blog posts here might also be useful.

kohlerm
A: 

It sounds like you are using an application managed EntityManager. You will need to call close the EntityManager yourself, it's part of the spec. You will also need to close the EntityManagerFactory when you shutdown your webapp.

I'd recommend using something like OpenEJB or Springframework to manage the EntityManager/EntityMangerFactory for you.

Ruggs
A: 

As @Ruggs said if you are managing the EntityManager lifecycle yourself (as opposed to having CMP Container Managed Persistence done by a J2EE) then you need to close the EntityManager yourself or at least call EntityManager.clear() to detach entities.

EntityManager are lightweight object so there is no need for just having one, you can create one for each transaction and close it after the transaction is committed.

All the entities that load/persist through an EntityManager stay in memory until you explicitly detach the entities from it (via EntityManager.detach() or EntityManager.clear() or EntityManager.close()). So it's better to have short-lived EntityManagers. If you persist 1000000 entities via the same EntityManager without detaching them after you will get a OOME (doesn't matter if you persist each entity in it's own EntityTransaction).

It's all explained in this post http://javanotepad.blogspot.com/2007/06/how-to-close-jpa-entitymanger-in-web.html.

As an example (taken from the earlier post) if you want to avoid "memory leaks" you should do something like this (if you are not using CMP):

EntityManager em = emf.createEntityManager();

try {
  EntityTransaction t = em.getTransaction();
  try {
    t.begin();  
    // business logic to update the customer
    em.merge(cust);
    t.commit();
  } finally {
   if (t.isActive()) t.rollback();
  }
} finally {
  em.close();
}
ecerulm