S2Container と Tomcat のリロード

http://d.hatena.ne.jp/t-katochin/20060623/1151082516
の最後で指摘されてるように,Tomcat 上で S2AOP を使うとリロードされても S2Container が GC されず,メモリ不足で例外が発生する場合があります.
この現象は以前から聞いてはいましたが,きっちり調べることはしていませんでした.
理由は

  1. 運用環境でリロードなんてあり得ない.
  2. 開発/テスト環境では Tomcat を再起動すればいい

ということで,致命傷になるとは考えていなかったためです.


が,しかし.
某巨大掲示板でも困ってるという人がいるので調べてみました.
まず,かとちんご指摘の循環参照について.
S2AOP を使うとアスペクトが適用されるメソッド毎に 〜$$MethodInvocation$$ みたいな名前のクラスが作成されます.
こいつは

    public static class MethodInvocationTemplate implements S2MethodInvocation {
        private static Class targetClass;
        private static Method method;
        private static MethodInterceptor[] interceptors;
        private static Map parameters;
        ・・・

というように static フィールドを持っています.
このうち,parameters というフィールドに設定される Map にはアスペクトが適用されるコンポーネント定義 (ComponentDef) への参照が含まれます.
そして ComponentDefアスペクトが適用された (エンハンスされた) クラスへの参照を持ち,アスペクトが適用されたクラスは上の 〜$$MethodInvocation$$ への参照を持つので,めでたく循環参照となります.


その是非はともかく,この循環参照そのものは S2ContainerGC されない直接の原因ではありません.
Tomcat 上で普通に S2 を使う場合,S2 もアプリのクラスも WEB-INF/lib 以下に配置され,それらは Web アプリ毎に用意されるクラスローダー,WebappClassLoader によってロードされます.
S2AOP によってエンハンスされるクラスも同じ WebappClassLoader にロードされます.
上で循環参照しているクラスとそのインスタンスが全て単一の WebappClassLoader によってロードされるため,その外からの参照が無くなればクラスローダーもろとも GC されます.
よって,この循環参照自体は GC を阻害するものではありません.


が,しかし.
実際には S2AOP を使うと S2ContainerGC されません.
S2AOP を使わなければ GC されます.
この原因がよく分からなかったのですが,実は S2AOP を使っても使わなくても,WebappClassLoaderGC されずに残っていたのですね.
WebappClassLoader が到達可能だと,それによってロードされたクラスも GC されず,その static フィールドから到達可能なオブジェクトも GC されません.
つ・ま・り
〜$$MethodInvocation$$parameters フィールドから到達可能であるため,S2AOP を使うと S2ContainerGC されなくなってしまうわけです.
実際には Tomcat じゃなく,JUnit なんかで試しても S2Container をロードしたクラスローダーが GC されていないことが分かりました.
し・か・も
GC されないのは最初に S2Container などをロードするのに使われるクラスローダーだけで,リロードされた後のクラスローダーなどは GC されちゃったり.


結局,その原因は commons-logging (の使い方) だったようです.
たぶん有名な話なのだと思いますが,LogFactory#release() とか使って Log なんかを解放してあげないといけないのね.
http://wiki.apache.org/jakarta-commons/Logging/UndeployMemoryLeak?action=print
http://jakarta.apache.org/commons/logging/guide.html#Classloader_and_Memory_Management
とはいえ,commons-logging も WEB-INF/lib にあって同じクラスローダーからロードされているわけで...
ちょっと腑に落ちないところはありますが,LogFactory#release() を呼んであげることで S2Container もそれをロードしたクラスローダーも GC されるようになりました.
trunk (S2.4 系) は既に修正&コミット済みです.
ついでに,S2Container#destroy() の際に ComponentDef や子の S2Container への参照をクリアするようにしました.
S2.3 系も近日中にコミットする予定.


そんなわけで (どんなわけで?),結論としては commons-logging の作法を守っていなかった S2 本体がメモリリークしていたということになります.心より恥じる.
Tomcat のリロードで悩んでいた方にはお詫び申し上げます.
それから,この問題に気づくきっかけを頂いたかとちんに感謝します.


Mensware in Milan Spring/Summer 2007

夏はまだこれからなのに秋冬の新作が入荷し始めた今日この頃ですが,ミラノでは早くも春夏コレクションがスタート!!
初日は JIL SANDERDolce & GabbanaBurberry Prorsum,Prada など.

JIL SANDER

http://www.vogue.co.uk/shows/photos/Default.aspx?ShowID=3586
秋冬同様,ボックス型のシルエットの細身のパンツ.
ようするに Raf らしいコレクションってことね.
おいらは Milan 時代がよかったよ...
Raf の JIL はおいらには魅力がないっす.

Burberry Prorsum

http://www.vogue.co.uk/shows/photos/Default.aspx?ShowID=3593
Christopher Bailey はシーズン毎にイメージがガラリと変わることが多いわけですが,ちょっとクラシックというか London 色が強かった最近と比べると軽やかになった感じ.
でもでも,そんなに好みという感じでもなさそう.
グレーが多いね.

Roberto Cavalli

http://www.vogue.co.uk/shows/photos/Default.aspx?ShowID=3713
Tom Ford,Milan Vukmirovic が去った今,オイラ好みの色っぽさを一番期待できそうなのがここかなとか思ったり.
でも,これだ! ってのは見当たらず.


春夏最大の注目はやはり GUCCI
John Ray が去って Frida Giannini による最初のメンズコレクション.
レディースみたいにプリントであふれてたらどうしよう...
この秋冬のレディースの雰囲気だったら悪くないかもしれないけど,春夏 (06SS) の雰囲気だったらイヤだなぁ.
ともあれ (JW),GUCCI は明後日.楽しみ♪