Webアプリケーション開発の際の注意事項(2)
初回の記事は以下。
Webアプリケーション開発の際の注意事項 - HHeLiBeXの日記 正道編
某所(何処)での某氏(誰)の報告が気になったので、シンプルケースで検証。
なんでも、java.io.ObjectStreamClass#lookup() を呼ぶだけでクラスローダーが残ってしまうという。理由は知らないけど、手元の WAS v6.1 Trial のライセンス期限がそろそろ切れるはずなので勢いで(謎)
問題となるコーディング(続き)
java.io.ObjectStreamClass#lookup() で Serializable なクラスを指定する
もっともシンプルなコード。まずは Servlet クラス。
import java.io.ObjectStreamClass; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public final class TestServlet extends HttpServlet { /** * <code>serialVersionUID</code> のコメント */ private static final long serialVersionUID = -822379849329082564L; public void init(ServletConfig config) throws ServletException { super.init(config); ObjectStreamClass.lookup(FooBean.class); } public void destroy() { try { } finally { super.destroy(); } } }
この中で使用されている FooBean クラス。
import java.io.Serializable; public class FooBean implements Serializable { /** * <code>serialVersionUID</code> のコメント */ private static final long serialVersionUID = -1775216435398915038L; }
これを前回と同様にデプロイし、何度か起動と停止を繰り返してみると、javacore には見事に TestServlet が残っている。
ちなみに、ObjectStreamClass#lookup() を呼ばなければ当然きれいに停止する。
ところで、java.io.ObjectStreamClass ってなんだ‥と思ってソースを見てみると、soft reference を保持していると思しきコードが散見される。
TODO:
シリアライズを実行する
先の ObjectStreamClass が ObjectInputStream や ObjectOutputStream で使用されているということなので、シリアライズしてみた。
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public final class TestServlet extends HttpServlet { /** * <code>serialVersionUID</code> のコメント */ private static final long serialVersionUID = -822379849329082564L; public void init(ServletConfig config) throws ServletException { super.init(config); try { ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream()); out.writeObject(new FooBean()); out.flush(); out.close(); } catch (IOException e) { throw new ServletException(e); } } public void destroy() { try { } finally { super.destroy(); } } }
FooBean クラスは同様だけど一応。
import java.io.Serializable; public class FooBean implements Serializable { /** * <code>serialVersionUID</code> のコメント */ private static final long serialVersionUID = -1775216435398915038L; }
これを前回と同様にデプロイし、何度か起動と停止を繰り返してみると、やはり javacore には見事に TestServlet が残っている。
ただ、(ObjectStreamClass#lookup() を呼んだ場合もそうだと思うが)初回起動も含めて12回の起動と停止としたところで残っていた参照が11個。さらに追加で10回の起動と停止をしたところで残っていた参照が11個。初回起動時に残っていたクラスローダーはいなくなっていたので、メモリの状況が変わるとそのうち回収されるらしい。その辺が soft reference が示す挙動なのだろう。