Sun / OracleのJVMについては、GCアルゴが新世代を1つのエデンリージョンと2つのサバイバーリージョンに分割していることを読みました。私が疑問に思っているのは、なぜ1つだけではなく、2つの生存地域なのかということです。アルゴは、エデンと1つのサバイバーリージョンの間でピンポンを続けることができます(2つのサバイバーリージョンの間で現在行われている方法)。または、このアプローチに欠点はありますか?
7 に答える
JRockitのGC実装は、単一のエデンと単一のサバイバースペースで、あなたが提案したように機能すると思いますが、それについては引用しないでください。
HotSpot JVMの2つのサバイバースペースの理由は、断片化に対処する必要性を減らすためです。新しいオブジェクトはエデンスペースに割り当てられます。すべてうまくいっています。それがいっぱいになったら、GCが必要です。古いオブジェクトを殺し、生きているオブジェクトをサバイバースペースに移動します。サバイバースペースでは、古い世代に昇格する前にしばらく成熟することができます。これまでのところまだ良いです。しかし、次にエデンスペースが足りなくなったときは、難問があります。次のGCがやって来て、エデンとサバイバースペースの両方のスペースをクリアしますが、スペースは隣接していません。だから、
- エデンからの生存者を、GCによってクリアされた生存者スペースの穴に合わせてみてください。
- サバイバースペース内のすべてのオブジェクトを下にシフトして断片化を排除してから、サバイバーをそこに移動しますか?
- 「ねじ込みます。とにかくすべてを移動します」と言うだけで、両方のスペースからすべてのサバイバーを完全に別のスペース(2番目のサバイバースペース)にコピーします。これにより、きれいなエデンとサバイバースペースができます。次のGCでシーケンスを繰り返しますか?
質問に対するSunの答えは明らかです。
マイナーガベージコレクションの操作後、2つのサバイバースペースの役割が逆転します
2つのサバイバースペース。これらは、少なくとも1つのマイナーなガベージコレクションを生き残ったが、古い世代に昇格する前に到達不能になる別の機会が与えられたオブジェクトを保持します。それらの1つだけがオブジェクトを保持し、もう1つはほとんどの場合未使用です。
マイナーガベージコレクションの操作中に、ガベージであることが判明したオブジェクトにマークが付けられます。コレクションを生き残ったエデンのライブオブジェクトは、未使用のサバイバースペースにコピーされます。使用中のサバイバースペース内の生きているオブジェクトは、若い世代で再利用される別の機会が与えられ、未使用のサバイバースペースにもコピーされます。最後に、「十分に古い」と見なされる、使用中のサバイバースペース内の生きているオブジェクトが古い世代に昇格されます。
マイナーガベージコレクションの最後に、2つのサバイバースペースが役割を交換します。エデンは完全に空です。使用中のサバイバースペースは1つだけです。そして、古い世代の占有率はわずかに増加しました。ライブオブジェクトは操作中にコピーされるため、このタイプのガベージコレクタはコピーガベージコレクタと呼ばれます。
出典:上記は、 CharlieHuntとBinuJohnによるJavaPerformanceの83ページからの抜粋です。
若い世代:それは短期間住んでいて、2つのスペースに分かれている場所です:
エデンスペース:新しいオブジェクトがメモリプールに割り当てられます。ほとんどのオブジェクトは、作成後すぐに逆参照され、到達不能になると想定されています。逆参照されていないオブジェクトは、新世代のガベージコレクターによってサバイバースペースにコピーされます。いくつかの特殊なケースでは、古い世代のプールに直接コピーされる場合があります。
サバイバースペース:これらの2つの小さなスペースは、若い世代のガベージコレクションのサバイバーオブジェクトを保持します。存続しているオブジェクトは、ある存続者から別の存続者に(少数の)回数コピーされます。これにより、より参照解除されたオブジェクトを収集できます。
旧世代:長寿命のオブジェクトを保持する必要がある最大のメモリプール。オブジェクトがサバイバースペースを離れると、オブジェクトはこのプールにコピーされます。
永続的な生成:このかなり未知のプールは、すべてのクラスの情報を保持します。ほとんどのアプリケーションでは注意を払う必要はありません。多くのクラスを持つ一部のアプリケーションに適合させる必要がある場合があります。アプリケーションがクラスを永続的にロードおよびアンロードする場合にも、注意が必要な場合があります。
その他の利点:
- メモリの断片化
- GCのパフォーマンスが向上します
詳細を理解するのに役立つ詳細については、次のリンクを見つけてください
現在の回答はすべてメモリの断片化について語っています。これは、GCに世代が存在するもう1つの理由でもあります。
ランタイムは、「新しいオブジェクト」を指すすべての「古いオブジェクト」を記録します。これは、「ポインター」フィールドが更新されるたびに実行されます。次に、「マイナー」GCが実行されると、「新しい」オブジェクトのみをスキャンする必要があります。
何年にもわたって、「新しい」と「古い」だけでは不十分であることがわかってきました。「中年」の第3世代がいるのは良いことです。
世代のすべてのインスタンスをあるスペースから別のスペースにコピーすることと、メモリアドレス順に世代のスペースの先頭にコピーすることの長所と短所は何ですか?アイテムを順番に処理するには、アイテムごとに追加のポインターを追加する必要がありますが、「サバイバー」スペースの1つは不要になります。
2人の生存者は、マークとコピーのアルゴリズムの実装です。これらは、若い世代のGCで使用されます。ここでオプション3でライアンが述べたように
Javaのヒープメモリヒープメモリと呼ばれる領域に作成されたJavaオブジェクト。ヒープメモリは、JVMの起動時に作成され、Javaアプリケーションの実行時にヒープメモリが増減します。ヒープメモリがいっぱいになると、ガベージコレクタは未使用のオブジェクトを削除するため、ガベージコレクタは新しいオブジェクト用のスペースを作成します。
ヒープメモリは、次の2つの領域(または世代)に分割されます。
1.ヤングスペース。2.古いスペース。
1.若いスペースには、新しいオブジェクト用のエデンスペースがあり、2つのサバイバースペース(fromとto)があり、これら2つのサバイバースペースは常に同じサイズです。
2.サバイバースペースはサバイバーオブジェクトを格納するために使用されます。若いスペースがいっぱいになると、ガベージコレクターは特別な若いコレクションを実行して未使用のオブジェクトを削除します。古いスペース、したがって、より多くのオブジェクト割り当てのために若いスペースを解放します。
3.エデンスペースがいっぱいの場合、GCが実行され、このエデンスペースにオブジェクトが存在する場合、それらはサバイバースペースに移動されます。
4.若いスペースでは、GCは通常、高速なコピーアルゴリズムを使用します。毎回、サバイバーオブジェクトはサバイバースペースの1つにコピーされます。
5.サバイバースペースがいっぱいの場合、残りのライブオブジェクトは古いスペースに直接コピーされます。
6.旧空間では、GCは通常、Mark-Compactアルゴリズムを使用します。これは低速ですが、必要なメモリが少なくて済みます。
7.古い空間がいっぱいになると、そこにゴミが集められ、古い収集と呼ばれるプロセスが行われます。古い空間では、長い寿命のオブジェクトがそこにとどまります。
8.メモリ不足が発生します。古いまたはPermパーツに対してGCが実行されても、新しいオブジェクト用のスペースはありません。
9.ガベージコレクション中にオブジェクトが移動されます:eden-> survivor-> tenured(old space)