java.lang.OutOfMemoryError:Java堆空间 - 如何保存内存?

时间:2011-07-17 06:56:37

标签: java jsf tomcat jvm

我正在尝试通过设置JVM参数来调整我的JSF应用程序内存消耗,因为我出现内存不足错误。

我能够增加内存堆并每天重启服务器两次,但这不是解决方案......

JVM参数

-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

一切似乎工作正常,终身空间为0 MB,伊甸园空间持续清除但幸存者空间仍在增长,当它达到极限时,物体被移动到终身空间并且从未被释放。经过半天的运行应用程序后,我得到了内存不足的错误。所以我必须安排自动重启tomcat服务器。

enter image description here

所以我认为,我的应用程序中肯定存在一些问题,因为它的内存消耗对于如此小的应用程序来说太高了(每天大约有数千个数据库移动)。

我的部分代码是:

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;
  }
}

您能否告诉我,将对象保存(更新,删除)到数据库的最佳做法是什么,以便保存的对象不会留在内存中?

3 个答案:

答案 0 :(得分:4)

在保存/删除/更新数据库中的对象方面,您的内存问题与您正在执行的任何操作都极不相关。 PermGen空间通常不用于任何用户级对象。它用于意图永远被解除分配的事物,例如类定义,JVM状态的内部位等。

如果管理数据对象的方式存在问题,您会看到OutOfMemoryError抱怨没有剩余堆空间。但是要回答你的问题,一般来说,你的数据对象将在他们离开范围之后运行的下一个垃圾收集过程中被垃圾收集(意味着你不再在任何地方引用它们)。我怀疑你已经处理好了,因为你没有得到OutOfMemoryError问题。

如果您不在PermGen空间,可能是因为您的应用程序使用了大量库。遗憾的是,解决此问题的唯一方法是增加PermGen大小,例如:

-XX:PermSize=256m

请注意,这将显着减少应用程序可用的堆空间量,因此通常明智的做法是将总JVM内存分配增加相应的数量,例如:

-Xmx1130m

尝试一下,看看它是否适合你。

答案 1 :(得分:3)

试试这个。它还不完美,但我认为你必须摆脱Dao中的静态会话属性。请参阅hibernate docs:http://docs.jboss.org/hibernate/envers/3.5/javadocs/org/hibernate/Session.html

实现者不是线程安全的。相反,每个线程/事务应该从SessionFactory获取自己的实例。

您还可以在 Dao 内部获取会话,以便 Bean 不了解底层持久性机制,但我不想改变那么多

<强> 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) {....}
}

答案 2 :(得分:2)

如果你有“PermGen:Out of Memory”,它与任何伊甸园,幸存者和终身空间都无关。

它发生在permgen,“非堆”部分,与-XX相关:PermSize = 150m。尝试更大的尺寸。

或者,否则,JSP / servlet编译器/类加载器/弹簧上可能会发生内存泄漏,类也可能占用已分配的内存。尝试减少类的数量(不是instance0 icuding proxy或AOP生成的类。