2011年7月30日土曜日

red5をapplet化してみる。その4、クラスの再読み込み時のメモリー状態について調査

この記事はRed5関係ないね・・・

Red5のShutdownコマンドによる、TomcatLoaderの自爆動作によってGUI動作のRed5に停止をかけてみたところ内部のクラスデータ等がきれいに消えなかった・・・
この問題に対処するため、なんとかデータがきれいに消えるようにしたいと思っています。

そこでJavaのClassLoaderの挙動について少々しらべてみました。

やったのは、GUI側のコマンドで別のJarデータを読み込ませて、その中にある。com.ttProject.entry.Launcherクラスのlaunchとunloadのメソッドを実行して、動作を確認するというものです。
用意したクラスはSingleton形式のクラス1つ。staticアクセスメンバをもつのが1つ。通常のクラスが1つ。
どのクラスもDataClassのオブジェクトを保持している。
とします。

JavaのJarライブラリ読み込みについておさらいしておくと・・・

  1. JDKやJREのあるディレクトリのシステムJarと同じ階層に設置しているJarデータは一番はじめに読み込まれる。(再読み込み不可)
  2. 実行するときのディレクトリにあるJarデータや実行時に指定したJarライブラリは次に読み込まれる。(再読み込み不可)
  3. まったく関係ない階層に設置しているJarデータをClassLoaderで動的に読み込む。(再読み込み可能)
  4. 1、2、3に同じパッケージクラスがあった場合、数字の若い方(先に読み込まれた方)が優先される。
というふうになっています。
一応、今回読み込みにつかったjarファイルを公開するために、JMXtestのリポジトリにプログラムを追加していますが、上記の仕様の都合上。JMXtest.jarの1つ上の階層にjartest.jarをおいていただくと動作確認できます。それ以外の場合はたぶんclassLoaderの読み込みのところで例外がでるはず。

プログラムの動作は
  1. 実行ボタンを押す
  2. Jarデータをロード
  3. unloadメソッドを実行(前の呼び出しによるstatic経由の変数にアクセスしてデータをDumpしようと試みる)
  4. launchメソッドを実行(クラスオブジェクトを設置して保持する。)
結果
まず3の前のデータをDumpの部分。staticアクセスなら同じ変数にアクセスできるのかなと思いましたが、再読み込みしてしまうとクラス空間が違う形になるため、アクセス不可。
よって、前回のClassLoaderのインスタンスがなくなり、前回のClassLoader経由で動作しているクラス(Thread等)がなくなると消滅するようです。
4回ほどクラスを実行したところ。
メモリー状態はこんな感じ、com.ttProject.entry系のクラスが1つもないです。
実行完了した瞬間にアクセスするためのデータが蒸発しているようです。
ClassLoaderのオブジェクトをstatic化して、ロードした後に消滅しないようにしてすると・・・
ちゃんとcom.ttProject.entry系のデータがある。
複数回読み込みを実行したのですが、最後の1回分だけデータが保持されています。
(クラスが重複していない。DataClassが3つあるのはSingleton static normalの3つのオブジェクトのせい)
最後に、Threadで無限ループをつくってLauncherクラスに設置したメンバー変数にnullをわりあてるようにしてみた。
無限ループをつくったので、ClassLoaderがなくなってもThreadがのこってしまうので、クラスのUnloadが走らないようです。
実行を繰り返すと、同じ名前の読み込みクラスがどんどん増えていきます。
これをみると、ClassLoaderもしくはスレッドがなくならない場合はクラスの読み込みデータはのこったままになるようですね。

さて、読み込まれたクラスの情報はだいたいわかりました。
 ClassLoaderそのものが存在しているもしくは、読み込まれたクラスに関連づけられているスレッドが実行中だと、読み込んだクラスがのこったままになるみたいです。
 上記の2つがなくなった場合はSingletonやstaticによる変数へのアクセスだとしてもきれいに掃除されてしまうようです。

前回のred5の停止命令の場合はよけいなデータがのこったわけですが、その原因を次回、少々さぐってみたいと思います。

0 件のコメント:

コメントを投稿