Hibernate java.lang.OutOfMemoryError:Java堆空间

时间:2015-05-14 10:27:08

标签: java hibernate web-applications tomcat7

我有一个在Tomcat 7上运行的Java Web应用程序 - jdk1.7

此应用程序使用Spring 4.1.5.RELEASE和Hibernate 4.2.2.Final

我的问题是构建部分工厂的堆空间的OutOfMemoryException

这是我打开SessionFactory

的静态方法
public class GenericDAO {

    public static SessionFactory sessionFactory = null;
    public static ServiceRegistry serviceRegistry = null;

    Transaction tx = null;

    public static SessionFactory createSessionFactory() {
        Configuration configuration = new Configuration();
        configuration.configure();
        serviceRegistry = new ServiceRegistryBuilder().applySettings(
            configuration.getProperties()). buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        return sessionFactory;
    }
}

这是DAO的一个例子

public class SpecificDAO extends GenericDAO {
    public int save(MyObject item) {
        Session session = createSessionFactory().openSession();
        try {
            tx = session.beginTransaction();
            session.save(item);
            tx.commit();
            return item.getId();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
                 e.printStackTrace();
        } finally {
            session.close();
        }
        return -1;
    }
}

错误发生在包含

的行

sessionFactory = configuration.buildSessionFactory(serviceRegistry);

问题不会在部署时立即发生,但在使用2天后仍然存在

这是我的Hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 <hibernate-configuration>
<session-factory>
    <property name="connection.url">jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName</property>
    <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
    <property name="connection.username">username</property>
    <property name="connection.password">password</property>
    <mapping class="it.company.client.project.hibernate.MyObject"/>

    <!-- DB schema will be updated if needed -->
    <!-- <property name="hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>

4 个答案:

答案 0 :(得分:2)

您必须只创建一次会话工厂,因为它是一个重量级的对象,请参阅hibernate documentation了解其详细信息。

以下是doc应如何创建的示例代码:

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory(
                new StandardServiceRegistryBuilder().build() );
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

答案 1 :(得分:1)

最好在使用后刷新并清除会话,您可以同时使用

from("servlet:apiwrapper?matchOnUriPrefix=true")
.to("bean:httpHeaderSetter?method=setHttpHeaders")
.to("http://HOST/BASEPATH?throwExceptionOnFailure=false&amp;httpClient.authenticationPreemptive=true");

了解更多信息link1link2

答案 2 :(得分:1)

您正在为每次save()调用创建一个SessionFactory对象。

即你为每个save()调用重复创建一个新的SessionFactory,但是没有关闭内存中现有的SessionFactory对象。

调用save()多少次?会话中没有SessionFactory,这会导致内存泄漏。

SessionFactory是重量级对象,因此您可以在应用程序初始化时创建。您可以创建一个SingleTon来实例化SessionFactory。

答案 3 :(得分:0)

避免在每个DAO操作上实例化SessionFactory对象。它非常慢并导致内存泄漏。在this answer

中有更好的解释

如果您仍然使用Spring,最好委托Spring使用SessionFactory,处理事务和处理SQL异常。例如,save()方法将减少为一行代码sessionFactory.getCurrentSession().save(item);手动事务打开/提交/回滚应替换为@Transactional属性。此外,通常更好地将事务放在整个服务方法上,而不是放在每个DAO方法上,但它取决于业务逻辑。

Here示例如何使用Hibernate配置弹出上下文(仅适用于Google的第一篇文章)

我稍微采用了这个例子来解决当前的问题

@Repository
public class SpecificDAO {
    private SessionFactory sessionFactory;

    @Autowired
    public SpecificDAO(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Transactional(propagation=Propagation.REQUIRED)
    public int save(MyObject item) {
        try{
            sessionFactory.getCurrentSession().save(item);
        }catch (HibernateException e) {
            return -1;
        }
    }
}

Spring配置

<context:annotation-config/>
<context:component-scan base-package="it.company.client.project"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName"/>
    <property name="username" value="username"/>
    <property name="password" value="password"/>
</bean>
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>it.company.client.project.hibernate.MyObject</value>
            </list>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
                <prop key="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</prop>
                <prop key="hibernate.show_sql">false</prop>
                <!--prop key="hibernate.hbm2ddl.auto">update</prop-->
            </props>
        </property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>