[Seasar-user:1706] Re: OutOfMemoryError が発生してしまいます。

Koichi Kobayashi koichik
2005年 3月 31日 (木) 01:00:39 JST


小林 (koichik) です.

On Wed, 30 Mar 2005 18:40:37 +0900
Yokota Takehiko <[E-MAIL ADDRESS DELETED]> wrote:

> 「AOPを使って生成されたクラスがクラスローダーからアンロードされない
> のはJavaの仕様」ということですが、
>   S2ContainerFactory#create(String, ClassLoader)
> メソッドを使って生成したS2Containerオブジェクトをdestroy()した後
> 生成時に使用したクラスローダごと破棄すればメモリは解放されるので
> しょうか。

未確認です.ごめんなさい.
クラスローダーが回収されればそのクラスローダーによって
ロードされたクラスもアンロードされるのは確かなのですが,
問題はクラスローダーが回収されるかどうかですね.

S2AOP では,クラスローダーと Javassist が提供する
ClassPool へのマップを保持しています.
ClassPool は Javassist によってクラスを動的に生成するための
クラスローダーのようなものです.

そのマップは一応 WeakHashMap を使っているので,クラスローダーが
回収されればマッピングが取り除かれて ClassPool も回収されるはずです.
ClassPool の方も LoaderClassPath を通じてクラスローダーへの参照を
持っていますが,こちらも WeakReference も使って参照しているようです.

よって,S2AOP として保持しているクラスローダーへの参照は全て
弱参照なので,クラスローダーの回収を妨げることはないと思われますが,
実際に確認してみないと安心できませんね.
# 正確には通常の参照が一つありますが,使っていないので常に null です.


もうひとつ注意が必要なこととしては,生成されたクラスが
どのクラスローダーでロードされるかという問題があります.
現在の S2AOP では,最初にエンハンスの対象となるクラスを
ロードしたクラスローダーを使おうとします.
それが null の場合 (ブートストラップクラスローダーから
ロードされたクラス) にコンテキストクラスローダーを使おうとします.
S2ContainerFactory#create(String, ClassLoader) に渡された
クラスローダーはコンテキストクラスローダーに設定されますから,
このクラスローダーよりも優先的に使われるクラスローダーが
あるということになります.

多くの場合,エンハンスの対象となるクラスは S2 コンテナが
コンテキストクラスローダーからロードしたクラスになると思いますが,
そのクラスローダーが親クラスローダーに先に委譲する場合で,
親クラスローダーのクラスパスにターゲットのクラスが含まれていると,
エンハンスされたクラスも親のクラスローダーからロードされます.

この動きは CGLIB を参考にしたからで,強い理由があるわけでは
ありません.
実際には,CGLIB はコンテキストクラスローダーの前に自分自身を
ロードしたクラスローダーを使おうとしますが,S2AOP ではこれを
逆にしています (うろ覚え).
同じように,ターゲットのクラスローダーよりも先にコンテキスト
クラスローダーを使う方が望ましければ検討します.

これは例えば Tomcat における common や shared にあるクラスに
アスペクトをかけた場合に,エンハンスされたクラスは common や
shared のクラスローダーではなく,コンテキストクラスローダーで
ロードすべきかどうかということになります.

> 今そういうアプリの開発を計画しているので教えて頂ければ幸いです。

問題があればどんどん指摘してください.
可能な限り対応します.


-- 
<signature>
    <name>Koichi Kobayashi</name>
    <e-mail>[E-MAIL ADDRESS DELETED]</e-mail>
</signature>




Seasar-user メーリングリストの案内