CDI 应用程序和依赖范围会共同影响垃圾收集吗?
我们开始尝试使用 CDI 实施我们的后端服务。场景是这样的:
带有@Startup 的EJB 在部署EAR 时启动。一个 ApplicationScoped bean 被注入其中:
@ApplicationScoped
public class JobPlatform {
private PooledExecutor threadHolder;
@Inject @Any
private Instance<Worker> workerSource;
...
该 bean 还有一个 Observer 方法,当观察到事件时,该方法从 InstanceworkerSource 获取一个工作 bean 并将其放入 threadPool 中,最终在该线程池中运行完成。
一切工作顺利。然而......我们已经开始看到垃圾收集问题。 JMAP 堆直方图显示,有许多此类工作人员闲逛,未收集垃圾。
我们认为,这取决于 CDI 范围界定的结合。 @Dependant 的 API 页面 (http:// /docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html)更清楚地强化了文档中的内容:
- 注入到字段、bean 构造函数或初始化方法中的范围为 @Dependent 的 bean 实例是它所注入的 bean 或 Java EE 组件类实例的依赖对象。
- 注入生产者方法的范围为 @Dependent 的 bean 实例是正在生成的生产者方法 bean 实例的依赖对象。
- 通过直接调用 Instance 获得的作用域为 @Dependent 的 bean 实例是 Instance 实例的依赖对象。
因此,遵循以下原则:
- workerSource bean 绑定到 JobPlatform,因此具有 ApplicationScoped 生命周期
- 使用该实例检索的任何工作 bean 都绑定到它,因此具有 ApplicationScoped 生命周期
- 因为 ApplicationScoped 的 beanstore上下文(我对术语的了解在这里有点模糊)仍然引用了工作bean,它们没有被破坏/垃圾收集
有人使用CDI同意这一点吗?您是否遇到过缺乏垃圾收集的情况?如果有,您能建议任何解决方法吗?
工作人员不能处于应用程序范围内,但平台必须如此。如果我们要创建一个自定义 WorkerScope(呃哦……)并用它注释每个工作器类,这是否足以分离工作器和实例源之间的依赖关系?
Is it possible to destroy a CDI range? 也有一些建议。 我会看看,但想要一些关于范围界定是否看起来像一个有效理由的备份。
希望你能帮忙,谢谢。
We're starting to experiment with implementing our backend services using CDI. The scenario is this:
EJB with @Startup is started when EAR deployed. An ApplicationScoped bean is injected onto this:
@ApplicationScoped
public class JobPlatform {
private PooledExecutor threadHolder;
@Inject @Any
private Instance<Worker> workerSource;
...
The bean also has an Observer method, which, when an event is observed, gets a worker bean from the Instance workerSource and puts it on the threadPool, where it eventually runs to completion.
All working nicely. However... we've started to see garbage collection issues. A JMAP heap histogram shows that there are many of these workers hanging around, un-garbage collected.
We believe that this is down to the combination of CDI scoping. The API page for @Dependant (http://docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html) reinforces more clearly what's in the docs:
- An instance of a bean with scope @Dependent injected into a field, bean constructor or initializer method is a dependent object of the bean or Java EE component class instance into which it was injected.
- An instance of a bean with scope @Dependent injected into a producer method is a dependent object of the producer method bean instance that is being produced.
- An instance of a bean with scope @Dependent obtained by direct invocation of an Instance is a dependent object of the instance of Instance.
So, following this:
- The workerSource bean is bound to JobPlatform, and therefore has an ApplicationScoped lifetime
- Any worker beans retrieved using that instance are bound to it, and therefore have an ApplicationScoped lifetime
- Because the beanstore of the ApplicationScoped context (my knowledge of the terminology gets a bit hazy here) still has a reference to worker beans, they're not destroyed/garbage collected
Does anyone using CDI agree with this? Have you experienced this lack of garbage collection and, if so, can you suggest any workarounds?
The workers cannot be ApplicationScoped, yet the platform has to be. If we were to create a custom WorkerScope (uh ohhh...) and annotate each worker class with it, would that be sufficient to separate the dependency between worker and instance source?
There're also some suggestions at Is it possible to destroy a CDI scope? that I will look at, but wanted some backup on whether scoping looks like a valid reason.
Hope you can help, thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的理解是正确的。这是规范中的一个疏忽,将在 CDI 1.1 中修复。
Instance
可能会出现内存泄漏,就像您在长时间运行的作用域(例如SessionScoped
或ApplicationScoped
)中使用时所描述的那样。您需要做的是获取实例的 Contextual 或 Bean 并以这种方式销毁它。对于您正在做的事情,为了避免内存泄漏,您最好使用 BeanManager 方法来创建实例(这样您还将拥有 Bean 的句柄并可以销毁它) ) 而不是
实例
。Your understanding is correct. This was an oversight in the spec, and something that will be fixed in CDI 1.1.
Instance
can have a memory leak just like you've described when used in a long running scope such asSessionScoped
orApplicationScoped
. What you will need to do is get a hold of theContextual
orBean
for the instance and destroy it that way.For what you're doing, and to avoid the memory leak you're best off to use the BeanManager methods to create instances (that way you'll also have a handle on the
Bean
and can destroy it) instead ofInstance
.在研究实施 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&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12601344
或
org.jboss.seam.faces.util.BeanManagerUtils
While looking into implementing Jason's suggested workaround, I found some more resources relating to the issue:
The issue: https://issues.jboss.org/browse/CDI-139 and https://issues.jboss.org/browse/WELD-920
Example beanManager operations:
https://issues.jboss.org/browse/CDI-14?focusedCommentId=12601344&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12601344
or
org.jboss.seam.faces.util.BeanManagerUtils