Reputation: 772
All my business methods create a new EntityManager and explicitly close them in the finally block.
EntityManagerFactory entityManagerFactory = PersistenceManager.getInstance().getEntityManagerFactory(); //Singleton
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.persist(someEntity);
tx.commit();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (em!=null) {
em.close();
}
}
I have a very basic persistence.xml file defined. I am not really specifying anything other than the DB connection information.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="db" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>package.class</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="INFO" />
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.url"
value="url" />
<property name="javax.persistence.jdbc.user" value="scott" />
<property name="javax.persistence.jdbc.password" value=tiger" />
</properties>
</persistence-unit>
</persistence>
The behavior I see in the application is that the allocated memory starts to grow and eventually reaches the max limit till the point I start getting out of memory errors. After a while those errors clear and the JVM's allocated heap gets back to around 95% of max. I am assuming a GC occurs at this time although I have not attached a profiler to confirm.
Is this considered default behavior? What are some of best practises on tuning the cache. What properties can I set in the persistence.xml file to limit the maximum cache size? Can I do it globally or do I need to define it per entity class?
Upvotes: 0
Views: 1225
Reputation: 21165
Its hard to say what is holding onto your memory without looking at it with a profiler. The most common cause is usually reusing EntityManagers without clearing them, as the EntityManager is required to hold onto each managed entity for its lifespan unless cleared. You are not doing that with the code you've shown that persists entities, but you have not shown how you are reading them in, so it might be possible, and is more common when users manage the EntityManagers themselves rather than let the container do it for them.
To answer the question about EclipseLink caches: EclispeLink has a second level cache that will hold onto memory. The different cache types and options are shown here http://www.eclipse.org/eclipselink/documentation/2.4/concepts/cache002.htm By default it uses a softweakidentitymap, which has two parts; a cache that uses soft references and an identity map that uses weak ones. The soft references allow the object to be garbage collected if your application is no longer referenced, and has a size of 100 per descriptor by default.
The caching options for JPA are discussed on this page http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching and you can turn off the shared cache to see if that helps your application. I would be surprised it helps though. You mention 95% of the apps memory is still held after garbage collection occurs, which would indicate the application still has references to the resources.
I'd recommend though that you check what is holding onto your memory and evaluate if there are problems within your application, or just that your application requires a larger amount of memory than has been configured.
Upvotes: 1