読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

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:

  • java.io.ObjectStreamClass ってなんだ?
  • soft reference のターゲットオブジェクトが GC の対象になる日はいつ?
シリアライズを実行する

先の 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 が示す挙動なのだろう。