Eclipselink可防止未缓存的查询结果被垃圾回收

时间:2016-11-01 13:31:58

标签: java jpa garbage-collection eclipselink

情况

在我的应用程序中,我使用Eclipselink v2.5.2作为JPA提供程序。在Weblogic v12.1.3和Java 8中运行。

每天晚上都要完成一项大任务,我的应用程序会在数据库中查询一整天的数据(在Java对象中大约200 MB), JPA不应缓存此数据。所有涉及的实体都有@Cacheable(false)注释。 为了处理这些数据,还要从数据库中获取一些配置,这些实体和查询结果应该由eclipselink缓存。 到期时间为1分钟,缓存类型为SOFT_WEAK。这意味着当内存不足时,可以相对快速地清除缓存。 Eclipselink中的共享缓存模式全局设置为DISABLE_SELECTIVE

大型任务由无状态EJB执行,数据和配置在一个事务中从数据库中检索,但是由不同的 无状态EJB,由Weblogic注入自己的EntityManager(使用相同的@PersistenceContext)。

对于针对数据库执行的速度和查询,缓存按预期工作。

问题

但是,在进一步查看应用程序的内存使用情况时, 我注意到在每日任务之后,使用的内存量大约高200mb,并且通过强制此任务连续运行几次(超过1分钟), 我可以让应用程序耗尽内存(并最终抛出OutOfMemoryError)。

在注意到这一点之后,我检查了一个堆转储(见截图),并确认Eclipselink正在阻止垃圾收集器收集大数据集。 我将这个heapdump解释如下(红色添加是我使用Eclipse Memory Analysis的结论,' inspect' window):

  1. 此数据保存在' queryResults' IdentityMapManager的属性(第3行)
  2. 在此缓存中是我的一个对象(缓存的JPA实体,用作缓存查询中的参数)。
  3. 在这个实体中是对RepeatableWriteUnitOfWork的引用,我在“检查”中找不到它。窗口作为我的实体的属性。
  4. 最终引用另一个IdentityMapManager
  5. 我的大型查询的数据在此处,在“identityMaps”下进行。 IdentityMapManager的属性。
  6. enter image description here

    在我的示例中,我运行了3次大型任务,这将导致相同数据的3倍(大集和配置)。 Eclipselink保持每次运行的完整副本。

    可能的解决方法

    我发现调用entityManager.getEntityManagerFactory().getCache().evictAll();会清理这些数据。我怀疑只清除这里涉及的查询的缓存也会这样做。

    问题

    我想知道为什么Eclipselink会保留大数据集。有没有我做错了,或者这是Eclipselink中的一个错误?

    此外,我想知道Eclipselink何时会清理这些数据,当我的初始尺寸为'是否已达到查询,或者是否会更早清除?

    编辑

    • 在缓存查询中用作参数的实体包含一个延迟加载的列表。 (this post提示可能导致其上下文保持活动状态)

0 个答案:

没有答案