首页 > 解决方案 > 调试内存泄漏 - org.hibernate.engine.StatefulPersistenceContext

问题描述

有一个服务连接到 Oracle DB 以读取数据,它使用Hibernate-3.6SpringData-JPA-1.10.x。堆转储频繁生成,导致主机内存不足。

在使用 Eclipse MAT 分析了几个 heapdump 之后,发现大部分内存是在org.hibernate.engine.StatefulPersistenceContext -> org.hibernate.util.IdentityMap -> java.util.LinkedHashMap的一个实例中积累的。

在此处输入图像描述 泄密嫌疑人说

线程 java.lang.Thread @ 0x84427e10 ... : 29 保留总大小为 1,582,637,976 (95.04%) 字节的局部变量。

内存在“”加载的“java.util.LinkedHashMap”的一个实例中累积。

在 StackOverflow 上搜索它,它说 SessionFactory 应该是单例的,并且 session.flush() 和 session.clear() 应该在每次调用之前调用以清除缓存。但是SessionFactory 没有在代码中显式初始化或使用

是什么导致了这里的内存泄漏(看起来每个查询的结果都被缓存而不是清除)以及如何解决它?

有关 Spring Data 配置的更多信息:

TransactionManager 初始化为:

<tx:annotation-driven mode='proxy' proxy-target-class='true' />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   ....
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" depends-on="...">
   ....
</bean>

为了与表交互,声明了一个扩展 Spring Data RepositoryJpaSpecificationExecutor的接口。两者都输入到它将处理的域类中。

API 活动方法具有注释@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)

标签: javahibernatememory-leaksspring-data-jpasessionfactory

解决方案


根据您的描述,这是我期望发生的事情:

Hibernate(实际上通常是 JPA)保留对它在会话生命周期内加载或保存的所有实体的引用。

在典型的 Web 应用程序设置中,这不是问题,因为。一个新会话从每个请求开始,并在请求完成后关闭,并且不涉及那么多实体。

但是对于您的应用程序,会话似乎在不断增长。我可以想象以下原因:

  • 某些东西一直在一个开放的会话中运行,而它从未关闭过。可能是批处理作业或定期运行的计划作业。

  • Hibernate 以这样一种方式配置,即它重用相同的会话而无需关闭它。

为了找到罪魁祸首,启用日志记录以打开和关闭会话。从https://hibernate.atlassian.net/browse/HHH-2425 org.hibernate.impl.SessionImpl判断应该是正确的日志类别,您可能需要跟踪级别的日志记录。

现在测试对服务器的各种请求,看看是否有任何会话打开但未关闭。


推荐阅读