JPA Hibernate DBCP Tomcat OutOfMemory

All*_*lan 8 java spring tomcat hibernate jpa

我在我的应用程序的新版本中收到每日OutOfMemory错误.我们为Tomcat分配了1.5 GB的堆.

使用Eclipse Memory分析器(http://www.eclipse.org/mat/),我在最短累积路径下得到了以下内容

org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList$Listable @ 0xa1566cc8  
    _head org.apache.tomcat.dbcp.pool.impl.CursorableLinkedList @ 0xa1566ca8  
      _pool org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool @ 0xa1566c38 
         connectionPool org.apache.tomcat.dbcp.dbcp.BasicDataSource @ 0xa1566980 
             dataSource org.springframework.orm.jpa.JpaTransactionManager @ 0xa0b01760 
                   <Java Local> java.lang.Thread @ 0xa4005900 ajp-8141-5 Thread 
Run Code Online (Sandbox Code Playgroud)

对此的进一步检查显示了许多重复的字符串,这些字符串是Hibernate查询.在我的应用程序主屏幕上,我加载了一个文档列表.查询的副本在堆转储中存在8,241次.

我还注意到org.apache.tomcat.dbcp.dbcp.AbandonedObjectPool中包含1 GB的堆.此文档查询正在加载文档二进制数据.它正在加载的文件大约是1MB.这让我怀疑垃圾收集器没有清理List.我们将从查询中删除不必要的数据,但它仍然让我担心对象仍然存在.

我正在使用JPA,Hibernate和Spring.我正在使用 @Transactional(readOnly=true)获取文档列表的方法.这是我的数据源Spring配置:

<jee:jndi-lookup jndi-name="jdbc/MyDB" id="myDataSource"/>

    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

        <property name="dataSource" ref="myDataSource"/>
        <property name="persistenceUnitName" value="WebPU"/>
        <property name="persistenceProvider">
            <bean class="org.hibernate.ejb.HibernatePersistence" />
        </property>
        <property name="jpaVendorAdapter">
            <bean
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="SQL_SERVER" />
                <property name="showSql" value="false" />
                <property name="generateDdl" value="false" />
            </bean>
        </property>

    </bean>

     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEmf" />
    </bean>
Run Code Online (Sandbox Code Playgroud)

我正在使用Tomcat提供连接池.这是我的配置:

<Resource auth="Container" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" initialSize="20"
  logAbandoned="true" maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/MyDB" password="pass" poolPreparedStatements="true" removeAbandoned="true" removeAbandonedTimeout="30" 
  type="javax.sql.DataSource" 
  url="jdbc:sqlserver://devmssql;databaseName=MY_DEV;responseBuffering=adaptive;port=1444" 
  username="user"/>
Run Code Online (Sandbox Code Playgroud)

服务层具有@Transactional.我的JPA查询如下所示:

public List<Document> getDocs(int cId, int lId, int ldId) { 
        CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Document> select = queryBuilder.createQuery(Document.class);

        Root<Document> from = select.from(Document.class);

        select.where(
                queryBuilder.and(queryBuilder.equal(from.get(Document_.cId), cId),
                queryBuilder.equal(from.get(Document_.lId), lId),
                queryBuilder.equal(from.get(Document_.ldId), ldId)));




        TypedQuery<Document> tq = getEntityManager().createQuery(select);

        final List<Document> rl = tq.getResultList();

        return rl;
    }
Run Code Online (Sandbox Code Playgroud)

我应该寻找什么来帮助确定内存泄漏的根本原因?是否有可能有助于此的DBCP,Hibernate或Spring设置?您在JPA查询代码中注意到可能有什么贡献吗?

Pio*_*ski 0

从方法返回之前尝试清除 EntityManager 缓存。首先调用EntityManager.flush()方法,然后调用clean()。如果您的 EntityManager“寿命”很长并且被许多数据库操作使用,这可能会有所帮助。

如果您使用 Spring,则可以在有问题的情况下放弃使用 Hibernate,转而使用普通 JDBC。Spring 为我们提供了 JDBCTemplate 来轻松处理查询,并且还提供了通用的事务管理接口,因此您可以将 Hibernate 操作与 JDBC 查询混合在一起。