I am trying to instantiate managed CDI beans using BeanManager, not an .select () instance. get ().
This was suggested as a workaround to the problem that I encountered ApplicationScoped beans and their dependency garbage collection - see CDI applications and dependent areas can conspire to affect garbage collection? for the background and this is the proposed solution to the problem.
If you use the Instance programmatic search method on the ApplicationScoped bean, the Instance object and any beans that you get from it ultimately depend on the ApplicationScoped bean and therefore share its life cycle. However, if you create beans using BeanManager, you have a handle to the Bean instance itself, and apparently it can explicitly destroy it, and I understand that it will be GCed.
My current approach is to create a Bean in the BeanManagerUtil class and return the bean, instance, and CreationalContext compound object:
public class BeanManagerUtil { @Inject private BeanManager beanManager; @SuppressWarnings("unchecked") public <T> DestructibleBeanInstance<T> getDestructibleBeanInstance(final Class<T> type, final Annotation... qualifiers) { DestructibleBeanInstance<T> result = null; Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type, qualifiers)); if (bean != null) { CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean); if (creationalContext != null) { T instance = bean.create(creationalContext); result = new DestructibleBeanInstance<T>(instance, bean, creationalContext); } } return result; } } public class DestructibleBeanInstance<T> { private T instance; private Bean<T> bean; private CreationalContext<T> context; public DestructibleBeanInstance(T instance, Bean<T> bean, CreationalContext<T> context) { this.instance = instance; this.bean = bean; this.context = context; } public T getInstance() { return instance; } public void destroy() { bean.destroy(instance, context); } }
From this in the calling code, I can get the actual instance, put it on the card for later retrieval and use as usual:
private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers = new HashMap<Worker, DestructibleBeanInstance<Worker>>(); ... DestructibleBeanInstance<Worker> destructible = beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier); Worker worker = destructible.getInstance(); ...
When I'm done with this, I can find the destructible shell and call destroy () on it, and Bean and its dependents should be cleaned:
DestructibleBeanInstance<JamWorker> workerBean = beansByTheirWorkers.remove(worker); workerBean.destroy(); worker = null;
However, after starting a few employees and leaving my JBoss (7.1.0.Alpha1-SNAPSHOT) for 20 minutes or so, I see that the GC is happening
2011.002: [GC Desired survivor size 15794176 bytes, new threshold 1 (max 15) 1884205K->1568621K(3128704K), 0.0091281 secs]
However, the JMAP histogram still shows the old workers and their dependent instances hanging around, unGCed. What am I missing?
As a result of debugging, I see that the context field of the created Bean has a context of the correct Worker type, no incomplete events, and no parentDependentInstances. He has a number of dependent conditions that are expected from the fields of the worker.
One of these fields in the Workplace is the Instance, and when I compare this field with that of the Worker obtained using the Instance program search, they have a slightly different CreationContext makeup. The “Instance” field at the Workplace, viewed through the “Instance”, has the employee under incomplete Instances, while the “Instance” field at the Workplace received from the BeanManager does not work. They both have identical parentDependentInstances and dependInstances.
This suggests that I did not correctly reflect the extraction of the instance. Could this contribute to a lack of destruction?
Finally, when debugging, I can see bean.destroy (), which is called in my DestructibleBeanInstance.destroy (), and this continues until ManagedBean.destroy, and I can see that the dependent objects are destroyed as part. release(). However, they still do not collect garbage!
Any help on this would be greatly appreciated! Thanks.