単例モード討論編:単例モードとごみ回収


Jvmのごみ回収メカニズムが長時間使わない単例モデルの対象を回収するかどうかは、確かに論争的な問題である.この部分を単独で編成する目的も、多くの博友とこの問題を広く議論するためだ.多くの人にこの文章を見てもらうために、ブロガーの皆さんは文章を読んだ後、「頂」をクリックして、この文章をできるだけ上位にランクインさせてください.筆者はここで謝った.
議論命題:1つの単例のオブジェクトが長い間使われていない場合、jvmのゴミ収集メカニズムに回収されません.
まず、なぜこのような疑問が発生したのか、筆者自身はこれまでごみ回収が単例モデルに与える影響を考えたことがなく、昨年まで本を読んだことがない.本では,j 2 ee応用において,jvmごみ回収メカニズムは,長い間使われていない単例類オブジェクトをごみとし,cpuが空いているときに回収すると述べている.以前読んだいくつかの設計モデルの本は、「javaとモデル」を含めて、jvmゴミ回収メカニズムが単例に与える影響については言及されていません.また,作業中に一例のオブジェクトが回収された経験もなく,作業中の多くの先輩が筆者に,これらの静的属性がロードされた後に解放されないため,できるだけ多くの静的属性を宣言しないようにと警告したことがある.そのためjvmごみ収集は単例対象を回収するという説に疑問を抱いている.だんだん、同僚やネット上の技術者の中で、この問題に対しても基本的に鮮明な対立があることが分かった.では、jvmは長い間使わなかった単例オブジェクトを回収するのではないでしょうか.
この問題に対して、筆者自身の観点は、回収しないということです.
次に、本人のテストコードを示します.
class Singleton {
	private byte[] a = new byte[6*1024*1024];
	private static Singleton singleton = new Singleton();
	private Singleton(){}
	
	public static Singleton getInstance(){
		return singleton;
	}
}

class Obj {
	private byte[] a = new byte[3*1024*1024];
}

public class Client{
	public static void main(String[] args) throws Exception{
		Singleton.getInstance();
		while(true){
			new Obj();
		}
	}
}

このプログラムの目的はj 2 eeコンテナをシミュレートすることであり、まず単例クラスをインスタンス化し、この単例クラスは6 Mメモリを占め、それからプログラムはデッドサイクルに入り、絶えずオブジェクトを作成し、jvmにゴミ回収を強要し、それからゴミ収集情報を観察し、ゴミ収集を行った後もメモリが6 Mより大きい場合、ゴミ回収は単例オブジェクトを回収しないことを説明する.
本プログラムを実行するために使用する仮想マシンはhotspot仮想マシン、すなわち私たちが使用する最も多いjavaが公式に提供する仮想マシンであり、通称jdk、バージョンはjdk 1である.6.0_12
実行時vm argumentsパラメータは、-verbose:gc-Xms 20 M-Xmx 20 Mであり、jvmがゴミ回収を行うたびにメモリ情報が表示されることを意味し、jvmのメモリは固定20 Mとする.
実行結果:
……
[Full GC 18566K->6278K(20352K), 0.0101066 secs]
[GC 18567K->18566K(20352K), 0.0001978 secs]
[Full GC 18566K->6278K(20352K), 0.0088229 secs]
……
実行結果からは,合計6 Mの空間が収集されていないことがわかる.従って,少なくともhotspot仮想マシンでは,ごみ回収は単例オブジェクトを回収しないと考える.
その後、hotspot仮想マシンのゴミ収集アルゴリズムはルート検索アルゴリズムを使用する関連資料をいくつか調べた.このアルゴリズムの基本的な考え方は、任意の「生きている」オブジェクトに対して、スタックまたは静的ストレージ領域に生存している参照に最終的に遡ることです.ルート(GC Roots)という一連の参照を起点として、これらのルートから検索を開始し、一連のパスを経てjavaスタック内のオブジェクトに到達できれば、このオブジェクトは「生きている」ものであり、回収できません.ルートとして使用できるオブジェクトは次のとおりです.
  • 仮想マシンスタック(スタックフレームのローカル変数テーブル)で参照されるオブジェクト.
  • メソッド領域のクラス静的属性が参照するオブジェクト.
  • メソッド領域の定数参照のオブジェクト.
  • ローカルメソッドスタック内のJNIの参照オブジェクト.

  • メソッド領域はjvmのメモリ領域であり、クラス関連の情報を格納するために使用されます.明らかにjavaで単一インスタンスモードで作成されたオブジェクトは、自分のクラスの静的属性によって参照され、第2条に合致するため、単一インスタンスオブジェクトはjvmゴミに収集されません.
    jvmスタック内の一例オブジェクトはゴミ収集されませんが、一例クラス自体は長時間使わないと収集されませんか?jvmはメソッドエリアにもゴミ収集メカニズムがあるからです.単一のクラスが収集されると,スタック内のオブジェクトはルートへの経路を失い,必ずゴミに収集される.これに対して,hotspot仮想マシンによるメソッド領域のゴミ収集方法を調べたところ,jvmアンインストールクラスの判定条件は以下の通りであった.
  • クラスのすべてのインスタンスは回収されました.つまりjavaスタックにはクラスのインスタンスが存在しません.
  • このクラスをロードしたClassLoaderはすでに回収されています.
  • このクラスに対応するjava.lang.Classオブジェクトはどこにも参照されず、クラスに反射的にアクセスする方法はどこにもありません.

  • 3つの条件が満たされている場合にのみ、jvmはゴミ収集時にクラスをアンインストールします.明らかに、単一のクラスは条件1を満たしていないため、単一のクラスもアンインストールされません.すなわち,単一クラスの静的参照がjvmスタック内の単一オブジェクトを指す限り,単一クラスと単一オブジェクトはゴミ収集されず,ルート探索アルゴリズムによれば,オブジェクトがゴミ収集されるかどうかは未使用時間の長さとは無関係であり,このオブジェクトが「生きている」かどうかだけである.もし1つのオブジェクトが長い間使用されていないで回収されるならば、収集アルゴリズムは最近最も長い未使用アルゴリズムであるべきで、最近最も長い未使用アルゴリズムは一般的にオペレーティングシステムの内外の保存交換の中で使って、もし仮想機のごみの回収の中で使うならば、あまりにも安全ではありませんか?以上が筆者の考えです.
    従って、筆者の観点は、hotspot仮想マシン1.6のバージョンでは、請求例における静的参照から単一オブジェクトへの結合を人為的に切断しない限り、jvmゴミ収集器は単一オブジェクトを回収しない.
    ブロガーの皆さんの発言を楽しみにしています.
     
    参考文献
    Java仮想マシン仕様
    Java hotspot仮想マシンメモリ管理
    Javaプログラミング思想
    Javaとモード
    デザインモード
    デザインモードの禅
    Java仮想マシンの理解