インスタンス.select()。get()ではなく、BeanManagerを使用してCDIマネージドBeanのインスタンスを作成しようとしています。BeanManagerを使用してCDI(Weld)Managed Beanを作成および破棄する方法は?
これは、ApplicationScoped Beanとその扶養家族のガベージコレクションに関する問題の回避策として提案されています。CDI Application and Dependent scopes can conspire to impact garbage collection?のバックグラウンドとこの推奨される回避策を参照してください。
ApplicationScoped BeanでInstanceプログラムルックアップメソッドを使用すると、Instanceオブジェクトとそこから取得するすべてのBeanは最終的にApplicationScoped Beanに依存するため、ライフサイクルを共有します。 BeanManagerでBeanを作成すると、Beanインスタンス自体にハンドルがあり、明らかに明示的に破棄することができますが、これはGCanされることを意味します。
私の現在のアプローチはBeanManagerUtilクラス内でBeanを作成し、豆、インスタンス、およびCreationalContextの複合オブジェクトを返すことです。このことから
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);
}
}
を、呼び出し元のコードでは、私はそれから得ることができます実際のインスタンス、後の検索のためのマップに入れ、そして通常通り使用します。その上
private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers =
new HashMap<Worker, DestructibleBeanInstance<Worker>>();
...
DestructibleBeanInstance<Worker> destructible =
beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier);
Worker worker = destructible.getInstance();
...
私はそれで終わりだとき、私は(破壊ラッパーを検索して破壊する呼び出すことができます)、およびBeanとその扶養家族は清掃する必要があります:
DestructibleBeanInstance<JamWorker> workerBean =
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;
しかし、いくつかの労働者を実行し、20分ほどのために私のJBoss(7.1.0.Alpha1-SNAPSHOT)を出た後、私は、GCはまだしかし、ショーをjmapのヒストグラムを
2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]
を発生見ることができます古い労働者とその従属インスタンスがぶら下がり、unGCed。私は何が欠けていますか?
デバッグによって、作成されたBeanのコンテキストフィールドに、正しいWorkerタイプのコンテキストがあり、incompleteInstancesおよびparentDependentInstancesがないことがわかりました。それには従業員のフィールドから予想される数のdependentInstancesがあります。
Worker上のこれらのフィールドの1つは実際にはInstanceであり、このフィールドをプログラムインスタンスの参照によって取得されたWorkerのフィールドと比較すると、若干異なるCreationalContextメイクがあります。 BeanManagerから取得したWorkerのInstanceフィールドは、incompleteInstancesの下にあるワーカー自体を持っているため、WorkerのInstanceフィールドはインスタンスを経由して検索されます。どちらも同じparentDependentInstancesおよびdependentInstancesを持ちます。
これは、インスタンスの取得を正しく反映していないことを示唆しています。これが破壊の欠如に貢献していますか?
最後に、デバッグすると、DestructibleBeanInstance.destroy()でbean.destroy()が呼び出され、これがManagedBean.destroyに渡され、依存オブジェクトが.releaseの一部として破棄されることがわかります。 ()。しかし、彼らはまだガベージコレクションを取得していません!
これに関するお手伝いをさせていただきます。ありがとう。
ありがとう、Jason。あなたが提案した変更を行ったが、まだガベージコレクションを見ていなかった。しかし、私が_full_ GCを待っていたとき、どちらのアプローチでもオブジェクトが収集されました - 成功!これは完全なGCの前のケースではありませんでした。 時間があれば、 '.createCreationContext(null)'と '.createCreationContext(bean)'の違いを説明できますか?私は拡張機能を書くためのドキュメントで前者を見てきましたが、タイプの 'bean'バージョン(私が意味するものを見れば)がまだ存在していなかったときのものだと思いました。助けてくれてありがとう。 –
仕様によると、Beanの非コンテキストインスタンスが提供されるため、そのBeanを作成するために実行されたコードの部分以外の参照はありません。私はPete Muirにいくつかのさらなる洞察を求めたが、まだ聞いていない。 – LightGuard