CDI应用程序和依赖范围可能合谋影响垃圾收集?

时间:2011-12-05 12:18:32

标签: garbage-collection scope cdi jboss-weld

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

在部署EAR时启动带有@Startup的EJB。 ApplicationScoped bean被注入到:

@ApplicationScoped
public class JobPlatform {

    private PooledExecutor threadHolder;

    @Inject @Any
    private Instance<Worker> workerSource;
...

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

一切顺利。但是......我们已经开始看到垃圾收集问题了。 JMAP堆直方图显示,这些工作人员中有很多人闲逛,没有收集垃圾。

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

  
      
  • 将范围为@Dependent的bean注入字段,bean构造函数或初始化方法的bean实例是注入它的bean或Java EE组件类实例的依赖对象。
  •   
  • 将一个带有@Dependent注入到producer方法中的bean的实例是正在生成的生成器方法bean实例的依赖对象。
  •   
  • 通过直接调用Instance获得的范围为@Dependent的bean实例是Instance实例的依赖对象。
  •   

所以,在此之后:

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

使用CDI的人是否同意这一点?你是否经历过这种垃圾收集的缺乏,如果是这样,你能建议任何解决方法吗?

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

Is it possible to destroy a CDI scope?我还会看到一些建议,但是想要确定范围是否合理的原因需要一些备份。

希望你能提供帮助,谢谢。

2 个答案:

答案 0 :(得分:9)

您的理解是正确的。这是规范中的疏忽,将在CDI 1.1中修复。 Instance可能会出现内存泄漏,就像您在SessionScopedApplicationScoped等长期运行范围内使用时所描述的那样。您需要做的是获取实例的ContextualBean并以此方式销毁它。

对于你正在做的事情,并且为了避免内存泄漏,你最好使用BeanManager方法来创建实例(这样你就可以在Bean上拥有一个句柄并且可以销毁它而不是Instance

答案 1 :(得分:2)

在考虑实施Jason建议的解决方法时,我发现了一些与此问题相关的资源:

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

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

org.jboss.seam.faces.util.BeanManagerUtils