JVMゴミ回収アルゴリズムの詳細

3705 ワード

前言
JVMメモリモデルでは、スタックメモリを新生代、旧年代の2つの領域に分けます.2つの領域の主な違いは、新生代が生存時間の短いオブジェクトを保存することです.旧年代が生存時間の長いオブジェクトを保存することは、生存時間の違いのほか、ゴミ回収戦略の違いもあります.JVMには以下の回収アルゴリズムがあります.
  • タグクリア
  • タグ整理
  • レプリケーションアルゴリズム
  • 世代別収集アルゴリズム
  • ごみの回収のアルゴリズムがあって、それではJVMはもし対象がごみの対象であることを確定するならばですか?JVMが生きているかどうかを判断するには、いくつかの独自の判断アルゴリズムがあります.
  • 引用記数
  • 達性分析
  • ごみ回収と判断対象の存在という2つの概念があった後,それらを徐々に分析する.
    JVMはどのようにしてオブジェクトが生存しているかを判断しますか?
    開発者に1つのオブジェクトが役に立つかどうかを判断させるのは簡単で、簡単に言えば はそのオブジェクトが回収できると考えている.次のプログラムコードがあるとします.
    public class App {
    
        public static void main(){
            checkFile("/");
        }
    
        public static boolean checkFile(String path ){
            File file = new File(path);
            return file.exists();
        }
    }

    プログラムが実行されると、checkFileが呼び出されたときのJVM図は、次のようになります.checkFileメソッドの実行が完了すると、その内部のローカル変数fileはスタックフレームとともにクリーンアップされ、このときJVMスタックに生存しているFileオブジェクトも無駄になります.
    人為的な判断が非常にはっきりしていれば、Fileオブジェクトはもう役に立たないことに気づきます.JVMに変えると、オブジェクトが生き残ることができるかどうかをどのように判断しますか?
    引用記数
    引用記数アルゴリズムの原理は比較的に簡単で、想像してみると1つのオブジェクトがcount属性を持っていて、そのオブジェクトを引用するたびにcountに1を加えて、JVMがそのオブジェクトが生存しているかどうかを判断する時にこのcount属性を検査して、この属性が0でないことを発見して、他のオブジェクトがこのオブジェクトを引用していることを説明します.checkFileメソッドの実行が完了するとcountは1減少して0になります.
    これにより,JVMは1つのオブジェクトが生存しているか否かを容易に判断できる.
    しかし、引用記数には明らかな欠点があり、循環引用の問題を解決できないことです.例えば、A-->B-->Aのような対象関係は、対象が回収すべきかどうかを判断する方法がありません.
    GC Root(達成性分析)
    なぜ アルゴリズムと呼ばれているのでしょうか.GC Rootによって1つのオブジェクトに到達することができれば、このオブジェクトは生存していることが理解される.では、どのような相手がGC Rootなのでしょうか.
    Java言語でGC Rootsとして使用できるオブジェクトは次のとおりです.
  • 仮想マシンスタックで参照されるオブジェクト(スタックフレームのローカル変数テーブル).
  • メソッド領域におけるクラス静的属性参照のオブジェクト.
  • メソッド領域で定数参照のオブジェクト.
  • ローカルメソッドスタック内のJNI(Nativeメソッド)が参照するオブジェクト.

  • やはり上記の例では、checkFileメソッドの実行時に、 fileGC Rootとすることができるので、実行中にJVMはこのFileオブジェクトを絶対に回収しません.
    しかし、checkFileの実行が完了すると、このスタックフレームはポップアップされ、その変数も解放され、対応するGC Rootがスタック内のFileオブジェクトに到達できないので、このとき、このオブジェクトが不要なオブジェクトであると判断し、安全に回収することができる.
    ごみ回収アルゴリズム
    タグクリア
    このアルゴリズムは,ルート集合(GC Root)からスキャンを開始するタグ,クリアの2段階に分けられ,1つのオブジェクトに到達するごとにそのオブジェクトが生存状態としてマークされ,クリア段階はスキャンが完了した後にマークされていないオブジェクトをクリアする.
    1枚の図で説明します.
    このアルゴリズムには、メモリフラグメントが発生し、図Bのように消去されるとメモリ領域が残り、後で大きなオブジェクトを割り当てる必要がある場合、連続したメモリが使用できないという欠点があります.
    マークアップ
    タグ整理は の問題はなく、ルートセット(GC Root)からタグをスキャンして不要なオブジェクトをクリアし、クリアが完了するとメモリを整理します.
    これによりメモリは連続しますが、オブジェクトを毎回移動しなければならないため、コストが高いという問題が発生します.
    アルゴリズムのコピー
    レプリケーションアルゴリズムはJVMを2等分化し、スタックが1 gに設定されている場合、レプリケーションアルゴリズムを使用するとスタックは2つの領域各512 mに分割されます.オブジェクトにメモリを割り当てるときは常にその中の1つを使って割り当てます.割り当てがいっぱいになるとGCはタグ付けを行い、生存しているオブジェクトを別の空白の領域に移動し、生存しているオブジェクトがあるかどうかをクリアします.このように繰り返し処理すると、常に空白の領域が合理的に利用されません.
    2つの領域が交互に使用されると、最大の問題は空間の浪費を招き、スタックメモリの使用率は50%にすぎないことです.
    ぶんかつかいしゅう
    新生代回収
    JVMのスタックは新生代と旧年代に分けられ、2つのタイプには異なる特性があり、それらの特性に基づいて異なる回収アルゴリズムを選択します.このアルゴリズムは新生代をEdenと2つのSurvivor区に分けます.
    上の図のように3つの領域が8:1:1の割合で割り当てられます.例えば、1000 mのスタックEdenは800 mで、2つのSurvivorはそれぞれ100 mを占めていますが、どのように動作していますか.
  • は常に1つのSurvivorが空いており、メモリ使用率は90%
  • です.
  • プログラムの実行は、Edenおよびそのうちの1つのSurvivor 1にメモリ
  • を割り当てる.
  • 実行Minor gcまで待つと、生き残ったオブジェクトは空のSurvivor 2
  • に移動する.
  • それからEdenSurvivor 2の中で引き続きメモリを割り当てて、Survivor 1は空いていて次回の使用を待っています
  • .
    これにより、メモリ使用率が90%に達し、メモリフラグメントも発生しません.
    古い年代のリサイクル
    古い世代のオブジェクトはごみ回収を行ってもオブジェクトの生存率が高いので,マーキングクリアやマーキングアレンジアルゴリズムを採用するのはよい選択であるが,ここでは述べない.