3

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?

gaffcz
  • 3,469
  • 14
  • 68
  • 108
  • Where do you store the session object? Is this an Oracle session? Especially in the DAO as its methods are `static`? – home Jul 17 '11 at 07:06
  • BTW: I think the session should be encapsulated inside the DAO. – home Jul 17 '11 at 07:07
  • Not sure, but I have heard that it is always a good practice to avoid static things because they produce memory leaks – Jaime Hablutzel Jul 17 '11 at 07:09
  • @home: Thank you. I'm not sure if I understand you well, but it's hibernate session on SQL database and methods in DaoSF are static. I've also tried open and close session in Dao.java, but it's the similar.. – gaffcz Jul 17 '11 at 07:13
  • If it's static what happens if 2 users access the Dao at the same time? How do you control that? I think you should have 1 Dao **instance** for each request. – home Jul 17 '11 at 07:16

3 Answers3

4

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.

aroth
  • 54,026
  • 20
  • 135
  • 176
  • I'm very sorry, It's a `java.lang.OutOfMemoryError: Java heap space`. I'm idiot. I've tried to change permSize and rise heap size, but it's not sulution. I'm only get the additional time, so I can restart tomcat server later... – gaffcz Jul 17 '11 at 07:20
3

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) {....}
}
home
  • 12,468
  • 5
  • 46
  • 54
  • Thank you very much, home!!! You're right, and I should first thinking before writing any code :) – gaffcz Jul 17 '11 at 07:34
  • @gaffcz: No prob. To be honest I don't know if this finally solves your problem. But before further exploring the OOM exception you should solve this one. – home Jul 17 '11 at 07:56
  • Thank you very much! I've rewrited DaoSF.java simillary and using not classes but instances of classes now. And I have couple of static methods (e.g. time calculations etc.), should I try to rewrite them the same way or it's normal to have some method in J2EE appl static? – gaffcz Jul 17 '11 at 12:09
  • `Static` methods are absolutely fine in Java. As long as they are stateless, e.g. they do not modify a static field on class level. Treat them as helps. Time calculations are a good example. See this: http://stackoverflow.com/questions/538870/java-static-methods-best-practices – home Jul 17 '11 at 16:27
2

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.

Dennis C
  • 24,511
  • 12
  • 71
  • 99
  • Thank you, I've tried to increase PermSize before, but as you can see on the picture, non-heap part is OK.. – gaffcz Jul 17 '11 at 07:11
  • @jaime - if the exception message says "PermGen: out of memory", then you ARE out of permgen memory. You are misinterpreting the monitoring graph. – Stephen C Jul 17 '11 at 07:18
  • I'm very sorry, I'm idiot!! It's not the permGen error, it was one hour age during a testing of application, it's heap space error :( – gaffcz Jul 17 '11 at 07:23