2016-04-23 8 views
3

gcがjava.lang.refパッケージのクラスでどのように動作するかテスト中です:Javaガベージリファレンスクラスの収集

以下は私のコードです。

public static void main(String [] args) { 

    int mb = 1024*1024; 

    //Getting the runtime reference from system 
    Runtime runtime = Runtime.getRuntime(); 

    System.out.println("##### Heap utilization statistics [MB] #####"); 
    ArrayList<Object> sb = new ArrayList<Object>(); 
    for(int i =0; i < 5000000; i++){ 
     sb.add(new Object()); 
     if(i % 1000 == 0) { 
      System.out.println(i); 
     } 
    } 

    SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb); 

    // System.gc() 

    //Print used memory 
    System.out.println("Used Memory:" 
     + (runtime.totalMemory() - runtime.freeMemory())/mb); 

    //Print free memory 
    System.out.println("Free Memory:" 
     + runtime.freeMemory()/mb); 

    //Print total available memory 
    System.out.println("Total Memory:" + runtime.totalMemory()/mb); 

    //Print Maximum available memory 
    System.out.println("Max Memory:" + runtime.maxMemory()/mb); 
} 

それは結果:

Used Memory:95, 
Free Memory:28, 
Total Memory:123, 
Max Memory:247 

そして、私は、コードを "にSystem.gc()" にコメントを元に戻した、とreran、結果は

Used Memory:1, 
Free Memory:122, 
Total Memory:123, 
Max Memory:247 

だったうん、まず、 ArrayListのインスタンスが収集されました。私が知っているように、SoftReferenceだけで参照されるインスタンスは柔らかく、左ヒープスペースがないためにGCが本当に必要なときに収集されます。コードの最初の結果の左スペースは約150(フリーmem 28 +左max mem 124)でした。私はArrayListのインスタンスが収集された理由を理解していません。

そして第二に、私は変更すると、コード実行:

sb.add(new Object()); -> sb.add(new StringBuffer(i)); 

をし、それが結果:

Used Memory:245, 
Free Memory:2, 
Total Memory:247, 
Max Memory:247 

なぜこれが違います?

そして最後に、私は修正して再度、コードを実行した:それは結果 を

SoftReference<ArrayList> wr = new SoftReference<ArrayList>(sb); 

から

WeakReference<ArrayList> wr = new WeakReference<ArrayList>(sb); 

へ:

Used Memory:245, 
Free Memory:2, 
Total Memory:247, 
Max Memory:247 

を私がしたのArrayListのインスタンスを推測していましたインスタンスがWeakReferenceによってのみ参照されたため収集されたので、これらのw弱い到達可能。しかし、彼らは集められなかった。

ここで、リファレンスの作業方法についての私の理解が間違っていると仮定します。

私は誰に教えてください。

Thxを^^

+1

これは実際に実行したコードと同じであってはなりません。 'sb'参照自体を決して削除しないので、' ArrayList'は確かに収集されません。 2回目と3回目のテストの間に 'sb = null;'行を削除していませんか? – Dolda2000

+0

オブジェクトがまだrefrenceを持っている場合、最初のgcはオブジェクトを削除しません。 System.gc()が実行されるかどうかは、jvmに依存するかどうかは決して確認できません。 – Jois

+0

Doldaが指摘したように、あなたは 'ArrayList'への強い参照を保持しています。もしあなたが見ている相違はおそらく 'ArrayList'自体が繰り返しサイズ変更されているためです。これは、あなたのループ中に徐々に大きな配列を割り当てます。 (そして、それらの配列はガベージコレクションされているものです。)また、 'StringBuffer'についてのあなたの質問が分かりません。 'StringBuffer'は、内部に配列を持っているので、普通の' Object'よりはるかに大きくなります。それゆえ、それははるかに多くのメモリを使用することが期待されるべきではありませんか? – Radiodef

答えて

2

埋め込まれた質問に答えるのが最も簡単です:あなたは、あなたが大容量化とStringBufferのインスタンスを作成しているiの増加に伴ってnew StringBuffer(i)new Object()を置き換え、それは驚きに来るべきではない場合にこれらのオブジェクトには、ステートレスなObjectインスタンスよりもはるかに多くのメモリが必要です。

私たちには難しい結果を提示し、その間には再現性がはるかに容易な結果になるので、主な質問はそれほど簡単ではありません。あなたのコードはあなたの言葉よりも、あるいはあなたのテスト環境の中に微妙な変化があったからです。原則として、両方の結果が可能ですが、あなたが行った変更とは全く関係ありません。

まず、System.gc()を呼び出すときに、ローカル変数のArrayListへの強い参照があるため、追加の参照が弱いか柔らかいかにかかわらず、完全に無関係です。ほとんどのセットアップとテストでは、ArrayListが発生し、含まれているオブジェクトはまだメモリを占有しています。

しかし、これは物語の終わりではありません。 “finalize() called on strongly reachable object in Java 8”で説明したように、オブジェクト参照は、この参照が使用されないことをJVMが証明できる場合は、強い参照が保持されていても収集されます。さらに説明すると、これが起こるかどうかは、JVMの最適化状態と実行されるコードによって決まるため、通常はインタプリタで実行される唯一のmainメソッドからなるサンプルプログラムでは起こりそうにありませんが、不可能ではありません。

しかし、この場合、このロジックは、SoftReference respへの参照を含むすべての未使用の参照に適用されます。 WeakReferenceインスタンス。そのReferenceオブジェクト自体が収集された場合、それは再び参照対象との意味が無関係になります。次に、ArrayList、含まれているオブジェクトと参照オブジェクトが一緒に収集されます。あなたが明示的にSystem.gc()を呼び出す前にnullsb変数を設定し、それは、あなたが異なる結果が発生する可能性がありますが、System.gc()はまだJVMにのみヒントであることを、心に留めておくと、後に参照オブジェクトにget()を呼び出す場合

無視しても何の効果もありません。