CDI应用程序和相关范围可以共谋影响垃圾收集? [英] CDI Application and Dependent scopes can conspire to impact garbage collection?
问题描述
我们正在开始尝试使用CDI实施我们的后端服务。情况是这样的:
具有@Startup的EJB在部署EAR时启动。一个ApplicationScoped bean被注入到这里:
@ApplicationScoped
public class JobPlatform {
private PooledExecutor threadHolder;
@Inject @Any
私有实例< 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 )更清楚地说明了文档中的内容:
< blockquote>
- 注入到字段,bean构造函数或初始化方法的范围为@Dependent的bean实例是bean或Java EE组件类实例的依赖对象,其中它被注入。
- 注入生产者方法的范围为@Dependent的bean实例是生产者方法bean实例的依赖对象。
- 通过直接调用Instance获得的具有@Dependent范围的bean的实例是Instance实例的依赖对象。
因此,遵循以下规则:
- workerSource bean绑定到JobPlatf orm,因此具有ApplicationScoped生命周期
- 使用该实例检索的任何工作bean都绑定到它,因此具有ApplicationScoped生命周期
- 因为ApplicationScoped上下文的beanstore(我对这个术语的了解有点朦胧)仍然有一个对worker bean的引用,所以它们不会被销毁/垃圾收集
ul>
使用CDI的人是否同意这一点?你有没有经历过这种垃圾收集的缺乏,如果是这样,你能提出任何解决方法吗?
工作人员不能成为ApplicationScoped,但平台必须是。如果我们要创建一个自定义的WorkerScope(呃ohhh ...)并用它注释每个工人类,那么这足以区分工人和实例源之间的依赖关系吗?
您的理解是正确的。这是规范中的一个疏忽,将在CDI 1.1中解决。 实例
可能存在内存泄漏,就像您在长时间运行的作用域(如 SessionScoped
或 ApplicationScoped
。你需要做的是为这个实例保存 Contextual
或 Bean
,并以这种方式销毁它。
对于你正在做的事情,为了避免内存泄漏,你最好使用BeanManager方法来创建实例(这样你就可以拥有一个处理 Bean
并且可以销毁它)而不是实例
。
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.
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 as SessionScoped
or ApplicationScoped
. What you will need to do is get a hold of the Contextual
or Bean
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 of Instance
.
这篇关于CDI应用程序和相关范围可以共谋影响垃圾收集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!