Java 调试内存泄漏-org.hibernate.engine.StatefulPersistenceContext

Java 调试内存泄漏-org.hibernate.engine.StatefulPersistenceContext,java,hibernate,memory-leaks,spring-data-jpa,sessionfactory,Java,Hibernate,Memory Leaks,Spring Data Jpa,Sessionfactory,有一个服务连接到Oracle DB以读取数据,它使用Hibernate-3.6和SpringData-JPA-1.10.x。堆转储经常生成,这会导致主机内存不足 在使用EclipseMat分析了几个堆之后,发现大部分内存都积累在一个org.hibernate.engine.StatefulPersistenceContext->org.hibernate.util.IdentityMap->java.util.LinkedHashMap实例中 泄密嫌疑人说 线程java.lang.thread

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

在使用EclipseMat分析了几个堆之后,发现大部分内存都积累在一个org.hibernate.engine.StatefulPersistenceContext->org.hibernate.util.IdentityMap->java.util.LinkedHashMap实例中

泄密嫌疑人说

线程java.lang.thread@0x84427e10…:29保持本地 总大小为1582637976(95.04%)字节的变量

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

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

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

有关Spring数据配置的更多信息:

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数据存储库JpaSpecificationExecutor。两者都被键入到它将处理的域类中


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

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

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

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

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

  • 某些内容始终在打开的会话中运行,但从未关闭。可能是批处理作业或定期运行的计划作业

  • Hibernate的配置方式是重用同一个会话而不关闭它

为了找到罪犯,请启用打开和关闭会话的日志记录。从
org.hibernate.impl.SessionImpl
判断,应该是正确的日志类别,您可能需要跟踪级别的日志记录


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

该问题包含有关创建某些bean的信息。但问题不在这里。问题在于您的代码中,您在哪里使用了这些bean

请检查您的密码。您可能正在循环中加载项。循环被一个事务包装


Hibernate创建巨大的中间对象,在事务完成(提交/回滚)之前不会清理这些对象。

发布Hibernate配置和初始化方式
SessionFactory
。同时打开调试日志并发布该日志。@a如问题中所述,SessionFactory未在代码中显式初始化或使用,因为我们使用的是Hibernate和Spring数据JPA。此服务有多个API与不同的表交互,查看IdentityMap的值,它属于特定的API。服务中的所有API都遵循相同的模式(使用Spring数据存储库和JpaSpecificationExecutor),并且无法确定为什么会在特定的API上发生这种情况。此外,该API的流量是正常的,没有突然增加。没有定期运行的计划/批处理作业。但是,由于使用情况,流量有时会很高。此外,要在会话打开/关闭时添加日志,是否需要在存储库文件中显式访问EntityManager中的会话obj?因为当前代码中未使用SessionFactory。你能详细解释一下吗?因为该方法是用
@Transactional(propagation=propagation.SUPPORTS,readOnly=true)
注释的,所以它应该为每个请求刷新会话缓存,对吗?通常这是通过Hibernate的标准配置和Spring事务机制来处理的。Spring关闭事务,这也会关闭会话。所以问题是:这是否如预期的那样发生。如果日志显示没有,我们可以查看配置以找出原因。支持意味着它将加入当前事务,或者在没有可用的当前事务时打开自己的事务。刷新可能在不同的时间发生(在选择之前、提交之前、在请求时),但仅将更改写入数据库。它不会清空会话。结束事务还应关闭会话,因此它应收集更多资源。