[Seasar-user:5892] Re: [S2Container]S2FrameworkTestCase/UnitClassLoaderの実装について

Koichi Kobayashi [E-MAIL ADDRESS DELETED]
2007年 1月 25日 (木) 18:00:38 JST


小林 (koichik) です.

Date:    Thu, 25 Jan 2007 13:29:36 +0900
From:    kubo <[E-MAIL ADDRESS DELETED]>
To:       <[E-MAIL ADDRESS DELETED]>
Subject: [Seasar-user:5886] [S2Container]S2FrameworkTestCase/UnitClassLoaderの実装について

> <現象>
> 
> S2TestCaseを継承したテストをEclipseのJUnitで一括実行すると
> Memoryの使用量がMethod毎に(ほぼ定量的に)増えていって、
> 最終的にOutOfMemoryになる。OutOfMemoryのMessageは、“PermGen space”。
> 
> TestMethodはおよそ200。それぞれincludeするdiconを必要なものだけに
> 絞っているが、少し長続きするだけで最終的にはOutOfMemoryとなる。

現象から一番考えられるのは,システムクラスローダーに
ロードされたクラスから,UnitClassLoader にロードされた
クラス(S2によってエンハンスされたクラス)への参照が
あるのではないかということです.
キャッシュなど.

そうなると UnitClassLoader がアンロードできず,
パーマネント領域が枯渇することになります.

> その場合、ClassLoadingする際に、parentのClassLoaderが該当Classを
> 読み込んでしまわないでしょうか?
> つまり、SystemClassLoaderがClassを読み込んでいないのでしょうか?

例えば Dao など,S2AOP でエンハンスされたコンポーネントを
取得して

System.out.println(dao.getClass().getClassLoader());

すれば,どのクラスローダーからロードされているか
確認できます.

> それとも、そのようなことはなく(少なくともOutOfMemoryの原因とは無関係)、
> UnitClassLoaderの実装は現状ので正しいのでしょうか?

少なくとも,エンハンスされたクラスは UnitClassLoader に
ロードされます.

> もしUnitClassLoaderは問題ないのであれば、その理由(仕組み)を
> 教えていただきたいのですがよろしいでしょうか?

S2AOP は,エンハンスしたクラスのバイトコード(byte[])を
コンテキストクラスローダーの ClassLoader#defineClass() で
ロードします.このメソッドは protected なのでリフレクション
経由で呼び出します.
org.seasar.framework.aop.javassist.AbstractGenerator の
toClass(ClassLoader, CtClass) メソッドがそれです.

そして,ClassLoader#defineClass() の実装は loadClass() と
異なり,親クラスローダーへ委譲しません.
そのクラスローダー自身にロードされます.

結果的に,UnitClassLoader#loadClass() を経由する
通常のクラスは親クラスローダー(システムクラスローダー)に
ロードされ,S2AOP によってエンハンスされたクラスのみが
UnitClassLoader にロードされます.

やり方は違いますが,同じようなことを
org.seasar.framework.container.util.MemoryLeakTest で
行っているので参考にしてください.


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




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