S_a_k_Uの日記みたいなDB

~サクゥーと呼ばないで~

java.lang.ref.Referenceの動きとキャッシュ

Java1.6.0_07
SoftReferenceとWeakReferenceの違いを調べてみる。
iBATISのキャッシュのreference-typeをどう設定しようかな?とした時に、SOFTとWEAKの動作を確認しときかったので。


WeakReferenceは、参照が切れたら、ということで動作はシンプル。
SoftReferenceは、Runtime.getRuntime().gc()でGCしても、参照が維持されてる。
ヒープサイズが拡張されるタイミングとかで、って感じがしないでもない。
+参照しているオブジェクトのサイズによっても、って感じでもある。
実際のコードはファイルのバイト配列のオブジェクトで、ファイルのサイズを変えて確認してみた。


参照が切れる時には、SoftReferenceの参照は一気に全て切れる。
世代(古い参照のみ)とかって感じではない。けど、世代が同じ状態で切りに言ってる?ヒープ領域の世代なんかも絡んでるかも?
と思って、jstatコマンドの-gcutilオプションで確認してみたら、old領域の使用率が100%になったタイミングで、一気に参照が切れてる。
でも、FullGCでは参照は切れてない。
オブジェクトサイズが大きい場合は、一気にold領域が増えるので、ヒープサイズが拡張されるタイミングで参照を切られる場合がある。
GCと、ヒープサイズの拡張と、参照の切断と、それぞれがマルチスレッドで処理されてる?ので、動きがピタっと合ってないだけかな?
なんかそんな動きっぽい。

【jstatコマンドのログ】
 S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
 0.00   0.00  58.59  99.68   2.55     40    0.023   231    3.391    3.415
 0.00   0.00  65.23  99.68   2.55     40    0.023   232    3.406    3.429
 0.00   0.00  65.82  99.68   2.55     40    0.023   234    3.435    3.459
 0.00   0.00  73.99  99.68   2.55     40    0.023   235    3.451    3.474
 0.00   0.00  82.13  99.68   2.55     40    0.023   236    3.466    3.489
 0.00   0.00  91.84  99.68   2.55     40    0.023   238    3.495    3.519
 0.00   0.00   6.93   1.41   2.55     40    0.023   241    3.538    3.561  ← 一気に参照が切れたタイミング
 0.00   0.00  21.10   3.02   2.55     40    0.023   242    3.552    3.575


で、


参照を切ったイベントで、ヒープサイズが減ってるじゃない(驚


でも、64[MB]→約36[MB]で最小サイズの512[KB]にはなってない(謎

【mapが保持しているオブジェクトの数、ヒープ最大サイズ、ヒープサイズ、ヒープ空きサイズ、ヒープ使用サイズ】
236	66,650,112	66,650,112	388,792		66,261,320 
1	66,650,112	66,650,112	65,304,512	1,345,600   ← 一気に参照が切れたタイミング
2	66,650,112	60,477,440	58,330,328	2,147,112
3	66,650,112	38,162,432	35,739,192	2,423,240  ← ヒープサイズが減ってる


動作を確認したコード。

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.text.Format;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

public class RefTest {

    public static void main(String[] args) throws Exception {
        RefTest test = new RefTest();
        test.test();
    }

    public void test() throws Exception {

        Map<Integer, Reference> map = new HashMap();
        int i = 0;
        Format f = NumberFormat.getInstance();

        while (true) {

            // GCするとどうなるか?
            //Runtime.getRuntime().gc();

            Object obj = 【それなりのサイズのオブジェクト】;

            // どちらかコメント外して確認 -------
            //map.put(i, new SoftReference(obj));
            //map.put(i, new WeakReference(obj));
            // ----------------------------------

            int cnt = 0;
            for ( int x = 0 ; x <= i ; x++ ) {
                if (map.get(x).get() != null) {
                    cnt++;
                }
            }

            long max = Runtime.getRuntime().maxMemory();
            long total = Runtime.getRuntime().totalMemory();
            long free = Runtime.getRuntime().freeMemory();

            // mapが保持しているオブジェクトの数、ヒープ最大サイズ、ヒープサイズ、ヒープ空きサイズ、ヒープ使用サイズ
            System.out.println(cnt 
                                + "\t" + f.format(max)
                                + "\t" + f.format(total)
                                + "\t" + f.format(free)
                                + "\t" + f.format(total - free)
                                );

            i++;

        }

    }
}
}


結論は、とりあえずSTRONGは止めてSOFTにしとくかな。