gaffcz
gaffcz

Reputation: 3479

java.lang.OutOfMemoryError: Java heap space - how to save memory?

I'm trying to tune my JSF application memory consuption by setting JVM arguments because I'm getting out of memory error.

I'm able to increase memory heap and restart the server twice a day, but it's not a solution...

JVM arguments:

-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSClassUnloadingEnabled
-XX:+CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=30
-XX:+CMSIncrementalMode
-XX:+CMSIncrementalPacing
-XX:ParallelCMSThreads=2
-XX:+UseCMSCompactAtFullCollection
-XX:+DisableExplicitGC
-XX:MaxHeapFreeRatio=70
-XX:MinHeapFreeRatio=40
-XX:MaxTenuringThreshold=30
-XX:NewSize=512m
-XX:MaxNewSize=512m
-XX:SurvivorRatio=2
-XX:PermSize=150m
-Xms1024m 
-Xmx1024m

Everything seems to work fine, tenured space is at 0 MB, eden space is continuosly cleared but survivor space is still growing and when it reach its limit, object are moved to tenured space and never been released. And after half a day of running application I get the out of memory error. So I have to schedule automatical restarts of tomcat server.

enter image description here

So I think, there must be some problem in my application, because its memory consuption is too high for such a small appl (about thousands movements in database per day).

There is part of my code:

Bean.java

/* save datalist */
public void save() 
{
  session = DaoSF.getSessionFactory.openSession();
  try
  {
    Dao.save(dataList);
  }
  catch  (Exception e) {...}
  finally
  {
    session.close();
  }
}

Dao.java

public static void save(List<? extends Object> dataList)
{  
  for (Object dataItem : dataList) 
  {  
    save(dataItem);  
  }  
}  
public static void save(Object dataItem) 
{ 
  try 
  { 
    Transaction tx = session.beginTransaction();  
    session.save(dataItem);  
    tx.commit();  
  }  
  catch(Exception e) {....}
}

DaoSF.java

public class DaoSF implements Serializable
{
  private static final long serialVersionUID = 1L;
  private static SessionFactory sessionFactory;
  private static Session hibSession;

  private static synchronized void initSessionFactory
  {
    Configuration config = new Configuration();
    config.configure("hibernate.cfg.xml");
    sessionFactory = config.buildSessionFactory();
    hibSession = sessionFactory.getCurrentSession();
  }

  public static SessionFactory getSessionFactory 
  {
    initSessionFactory;
    return sessionFactory;
  }

  public static Session getSession() 
  {
    return hibSession;
  }
}

Could you tell me, what are the best practices in saving (updating, deleting) of object to database so that the saved object don't stay in memory?

Upvotes: 3

Views: 5501

Answers (3)

home
home

Reputation: 12538

Try this. It's not yet perfect, but I think you must get rid of the static session attribute in Dao. See hibernate docs: http://docs.jboss.org/hibernate/envers/3.5/javadocs/org/hibernate/Session.html:

It is not intended that implementors be threadsafe. Instead each thread/transaction should obtain its own instance from a SessionFactory.

You can also obtain the session inside Dao itself, so that Bean does not have any knowledge of the underlying persistence mechanisms, but I did not want to change that much.

Bean.java

/* save datalist */
public void save() {
    Session session = nlul;
    try {
        session = DaoSF.getSessionFactory.openSession();
        /* one instance per call, 
         * ready for garbage collection after leaving this method
         */
        Dao mydao = new Dao(session);
        mydao.save(dataList);
    } catch  (Exception e) {...
    } finally {
        if (sessioN != null)
            session.close();
    }
}

Dao.java

private Session mysession = null;

public Dao(Session mysession) {
    this.mysession = mysession;
}

public void save(List<? extends Object> dataList) {  
    for (Object dataItem : dataList) {  
        save(dataItem);
    }  
}  

public void save(Object dataItem) { 
    try  { 
        Transaction tx = session.beginTransaction();  
        this.mysession.save(dataItem);  
        tx.commit();  
    }  
    catch(Exception e) {....}
}

Upvotes: 3

aroth
aroth

Reputation: 54836

It is extremely unlikely that your memory issues are directly related to anything you are doing with respect to saving/deleting/updating objects in your database. The PermGen space is generally not used for any user-level objects. It is used for things that are meant to never be deallocated, such as class definitions, internal bits of JVM state, and the like.

If there was an issue with how you are managing your data objects, you would be seeing an OutOfMemoryError complaining about there being no heap space left. But to answer your question, generally speaking your data objects will be garbage-collected on the next garbage collection pass that runs after they leave scope (meaning that you no longer have a reference to them anywhere). I suspect you are handling this fine already, as you are not getting OutOfMemoryError issues.

If you are out of PermGen space, it is probably because your application is using a large number of libraries. Sadly, the only way to fix this is to increase the PermGen size, like:

-XX:PermSize=256m

Note that this will essentially decrease the amount of heap-space that is available to your application, so it is usually wise to increase your total JVM memory allocation by a corresponding amount, like:

-Xmx1130m

Give that a try and see if it works any better for you.

Upvotes: 4

Dennis C
Dennis C

Reputation: 24747

If you have a "PermGen: Out of Memory", it is not very related to any eden, survivor nor tenured space.

It is happening on permgen, "Non-Heap" part, which is related to -XX:PermSize=150m. Try a larger size of it.

Or, otherwise, there may be a memory leak happening on the JSP/servlet compiler/classloader/spring that too may Classes occupied the allocated memory. Try to reduce number of classes(not instance0 icuding proxy or AOP generated classes.

Upvotes: 2

Related Questions