我在我的应用程序的新版本中收到每日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
对此的进一步检查显示了许多重复的字符串,这些字符串是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>
我正在使用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"/>
服务层有@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;
}
我应该寻找什么来帮助确定内存泄漏的根本原因?是否有可能有助于此的DBCP,Hibernate或Spring设置?您在JPA查询代码中注意到可能有什么贡献吗?
答案 0 :(得分:1)
答案 1 :(得分:0)
尝试从方法返回之前清除EntityManager缓存。首先调用EntityManager.flush()方法,然后调用clean()。如果您的EntityManager“长寿”并且许多数据库操作都使用它,这可能会有所帮助。
如果你使用Spring,你可以放弃使用Hibernate来解决有问题的情况,并使用普通的JDBC。 Spring为我们提供了JDBCTemplate,可以轻松地使用查询并提供常见的事务管理接口,因此您可以将Hibernate操作与JDBC查询混合使用。