应用程序作用域和依赖作用域可以共同影响垃圾收集



我们开始尝试使用CDI实现我们的后端服务。场景是这样的:

带有@Startup的

EJB在部署EAR时启动。一个ApplicationScoped bean被注入到:

@ApplicationScoped
public class JobPlatform {
    private PooledExecutor threadHolder;
    @Inject @Any
    private Instance<Worker> workerSource;
...

该bean还有一个Observer方法,当观察到一个事件时,该方法会从Instance workerSource获取一个工作bean,并将其放在threadPool中,最终运行到完成。

一切正常。然而……我们已经开始看到垃圾收集问题。JMAP堆直方图显示,有许多这样的工作线程挂在周围,未被垃圾收集。

我们认为这是由于CDI范围的组合。@Dependant的API页面(http://docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html)更清楚地强化了文档中的内容:

  • 将作用域为@Dependent的bean实例注入到字段、bean构造函数或初始化方法中,是该bean或Java EE组件类实例的依赖对象。
  • 将作用域为@Dependent的bean实例注入到一个生产者方法中,它是正在被生产的生产者方法bean实例的依赖对象。
  • 通过直接调用instance获得作用域为@Dependent的bean实例是instance的实例的依赖对象。

那么,接下来是:

    workerSource bean绑定到JobPlatform,因此有一个applicationscope的生命周期
  • 使用该实例检索的任何工作bean都被绑定到它,因此具有applicationscope生存期
  • 因为ApplicationScoped上下文的beanstore(我对术语的了解在这里有点模糊)仍然有对工作bean的引用,所以它们没有被销毁/垃圾收集

使用CDI的人都同意吗?您是否遇到过这种缺乏垃圾收集的情况?如果有,您能提出一些解决方法吗?

工作者不能是ApplicationScoped的,但是平台必须是。如果我们要创建一个自定义的WorkerScope,并用它注释每个worker类,这是否足以分离worker和实例源之间的依赖关系?

也有一些建议是否有可能破坏CDI作用域?

希望你能帮忙,谢谢。

你的理解是正确的。这是规范中的一个疏忽,将在CDI 1.1中修复。InstanceSessionScopedApplicationScoped等长时间运行的作用域中使用时可能会出现内存泄漏,正如您所描述的那样。您需要做的是获得实例的ContextualBean,并以这种方式销毁它。

对于你正在做的事情,为了避免内存泄漏,你最好使用BeanManager方法来创建实例(这样你也会有一个对Bean的处理,可以销毁它)而不是Instance

在研究如何实现Jason建议的解决方案时,我发现了与此问题相关的更多资源:

问题:https://issues.jboss.org/browse/CDI-139和https://issues.jboss.org/browse/WELD-920

beanManager操作示例:https://issues.jboss.org/browse/CDI-14?focusedCommentId=12601344&页面= com.atlassian.jira.plugin.system.issuetabpanels: comment-tabpanel #评论- 12601344

org.jboss.seam.faces.util.BeanManagerUtils

最新更新