Drunkシリーズ:DrunkのJVMガベージコレクションメカニズムとメモリ割り当て戦略

上の青いフォントをクリックして、「スター公式アカウント」を選択してください

高品質の記事、すぐに配達

99セットのJavaエンタープライズレベルの実際の戦闘プロジェクト

4000Gアーキテクト情報

リード:公式アカウントでは、飲んだ後に一連の技術記事を発表します。これらはすべて乾物であり、酔わないように願っています。

飲む前に開会の挨拶をする必要があります。前回の記事は皆さん読んだと思います。初めて飲んだのですが、レビューしたい方は引き続きレビューしてください!

次に、もう一度美味しいお酒を飲みましょう。そうすれば、お酒に合うおかずが欠かせないので、まずはおかず2品をお出しします。

1.参照カウント方法????

オブジェクトに参照カウンターを追加します。参照がある場合は常に、カウンター値は+1になります。参照が無効な場合は、カウンター値は-1になります。カウンターが0のオブジェクトは、それ以上できなくなります。利用される。

2.アクセシビリティの分析と計算????

「GCルート」となる一連のオブジェクトを起点として、これらのノードから下に向かって検索することで、検索されたパスを参照チェーンと呼びます。オブジェクトからGCルートへの参照チェーンがない場合、次のことが証明されます。オブジェクトは使用できません。

一部の飲酒者は理解できないかもしれません、GCルーツとは何ですか、私がそれを飲むかどうか教えてくれますか????

1.仮想マシンスタックで参照されるオブジェクト(スタックフレーム内のローカル変数テーブル)[メソッド内のnew()のオブジェクト]

2.メソッド領域のクラスstaticプロパティによって参照されるオブジェクト[staticA a = new A()]

3.メソッド領域の定数によって参照されるオブジェクト

4.ネイティブメソッドスタック内のJNI(通常はネイティブメソッド)によって参照されるオブジェクト

飲酒者がよりよく理解できるように写真に来てください

食べた後に乾杯が必要ですか????

3.到達可能性分析アルゴリズムを使用して、オブジェクトは存続または破壊されますか????

Javaは、到達可能性分析アルゴリズムを使用して、オブジェクトが生きているかどうかを判別します。

到達可能性分析アルゴリズムで到達可能でないオブジェクトは、「破棄する必要がある」わけではありません。現時点では、彼らは「保護観察」段階にあります。オブジェクトの死を真に発表するには、少なくとも2つのマーキングプロセスを実行する必要があります。到達可能性分析後にオブジェクトにGCルートに接続された参照チェーンがない場合、初めてです。フィルターをマークして実行します。フィルター条件は、このオブジェクトがfinalize()メソッドを実行する必要があるかどうかです。オブジェクトがfinalize()メソッドをカバーしていない場合、またはfinalize()メソッドが仮想マシンによって呼び出された場合、仮想マシンは両方のケースを「実行する必要がない」と見なします。このオブジェクトがfinalize()メソッドを実行する必要がある場合、このオブジェクトは、クラスへの割り当てなど、参照チェーン内のオブジェクトとの関係を再確立する限り、このメソッドの実行時に正常に保存されます。変数またはオブジェクトのメンバー変数。2回目にマークされたときに再利用されません。

ガベージコレクションアルゴリズム

1つ、マークスイープアルゴリズム???

最も基本的な収集アルゴリズムは、その名前と同様に、「マーキング」と「クリア」の2つの段階に分けられます。最初に、リサイクルが必要なすべてのオブジェクトにマークが付けられ、マークが完了した後、マークされたすべてのオブジェクトが均一にリサイクルされます。その主な欠点には明るい点があります。1つは効率の問題であり、マーキングとクリアの2つのプロセスの効率は高くありません。もう1つはスペースの問題であり、マークがクリアされた後、多数の不連続なメモリフラグメントが生成されます。 、およびスペースの断片化が多すぎると、後で発生する可能性があります。プログラムの実行中に大きなオブジェクトを割り当てる必要がある場合、十分な連続メモリを見つけることができず、事前に別のガベージコレクションをトリガーする必要があります。

第二に、複製アルゴリズム???

効率の問題を解決するために、「コピー」と呼ばれる収集アルゴリズムが登場しました。これは、使用可能なメモリを2つの等しい部分に分割し、一度に1つの部分のみを使用します。このブロックが使い果たされたら、残っているオブジェクトを別のブロックにコピーしてから、使用済みのメモリスペースを一度にクリーンアップして、半分の領域全体が再利用され、メモリ割り当て時にメモリが考慮されないようにします。断片化などの複雑な状況の場合、ポインタを移動してメモリを順番に割り当てるだけです。これは、実装が簡単で、実行が効率的です。このアルゴリズムのコストは、メモリを半分に減らすことであり、これは高すぎます。

3つのマークソートアルゴリズム???

マーキングプロセスは「マークスイープ」アルゴリズムと同じですが、後続の手順では、リサイクル可能なオブジェクトを直接クリーンアップするのではなく、残っているすべてのオブジェクトを一方の端に移動してから、端の境界の外側のメモリを直接クリーンアップします。 。

第四に、世代別収集アルゴリズムの使用???

商用仮想マシンの現在のガベージコレクションは、オブジェクトのライフサイクルに応じてメモリをいくつかのブロックに分割する「世代別コレクション」アルゴリズムを採用しています。一般に、Javaヒープは新世代と旧世代に分けられ、各世代の特性に応じて最適な収集アルゴリズムが採用されます。新世代では、ガベージコレクションのたびに多数のオブジェクトが停止し、少数のオブジェクトのみが存続することが判明した後、レプリケーションアルゴリズムが選択され、コレクションのレプリケーションコストを少量支払うことでコレクションを完了できます。生き残ったオブジェクト。老後は、オブジェクトの生存率が高く、割り当てを保証するための余分なスペースがないため、「マーククリーン」または「マークアンドソート」アルゴリズムを使用してリサイクルする必要があります。

メモリ割り当て戦略

一般に、オブジェクトのメモリ割り当てはヒープに割り当てられます。オブジェクトは主に若い世代のエデン領域に割り当てられます。場合によっては、古い世代に直接割り当てられることもあります。割り当てルールは100ではありません。 %修正済み。詳細は、現在使用されているガベージコレクターの組み合わせ、および仮想マシンのメモリ関連パラメーターの設定によって異なります。

1.オブジェクトは新世代のエデンエリアに割り当てられますか????

ほとんどの場合、オブジェクトは若い世代のエデンエリアに割り当てられます。Edenエリアに割り当てるための十分なスペースがない場合、仮想マシンはマイナーGCを開始します。コードを使用して飲酒者にデモンストレーションする

/**
 * 对象优先在Eden 区分配
 *
 * 虚拟机参数设置:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
 *  -verbose:gc 在控制台输出GC情况
 *  -Xms20M -Xmx20M -Xmn10M 限制Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下10MB分给老年代
 *  -XX:+PrintGCDetails 收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况
 * Created by lxs.
 * 2020/5/22 6:25 PM
 */
public class TestMinorGC {


    private static final int _1MB = 1024 * 1024;


    public static void main(String[] args) {
        byte[] obj1, obj2, obj3;


        obj1 = new byte[2 * _1MB];
        obj2 = new byte[2 * _1MB];
        obj3 = new byte[3 * _1MB];  // 发生Minor GC
    }


}

次の図に示すように実行します。

最初の赤いボックスは、このGCの結果、新生代の5650KBが448KBになることを意味します。

2番目の赤いボックスの合計5650KBは4544KBになりますが、これはそれほど減少していません。これは、2つのオブジェクトobj1とobj2が生きており、仮想マシンがリサイクル可能なオブジェクトをほとんど見つけられないためです。

3番目の赤いボックスは、エデンエリア、エリアからのサバイバー、およびエリアからのサバイバーを表します。メモリサイズの比率は8:1:1で、合計は正確に10MBです。

4番目の赤いボックスは老後の10MBです。

このGCの理由は、obj3にメモリを割り当てるときに、Eden領域が少なくとも4MB占有されており、残りのスペースがobj3に必要な3MBのメモリを割り当てるのに不十分であるため、マイナーGCが発生したためです。GC中に、仮想マシンは、既存の2つの2MBオブジェクトすべてをサバイバースペースに配置できないことを検出したため、事前に割り当て保証メカニズムを介して古い時代に移行する必要がありました。

GCが終了すると、3MBのobj3オブジェクトがEdenに割り当てられるため、プログラム実行の結果、Edenは3MB(obj3)を占有し、Survivorはアイドル状態になり、古い年齢は4MB(obj1、obj2)を占有します。これは、GCログで証明できます。

第二に、大きな物体は直接老後に入りますか????

/**
 * 大对象直接进入老年代
 *
 * 虚拟机参数设置:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:PretenureSizeThreshold=3145728
 *  -verbose:gc 在控制台输出GC情况
 *  -Xms20M -Xmx20M -Xmn10M 限制Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下10MB分给老年代
 *  -XX:+PrintGCDetails 收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况
 *  -XX:PretenureSizeThreshold=3145728 大于这个设置值的对象直接分配在老年代中,即大于3MB
 *  -XX:PretenureSizeThreshold 这个参数只对Serial和ParNew两款收集器有效,我的是用的Parallel Scavenge收集器,所以不顶用,我直接new了大一点的对象,7MB的直接分配到老年代了
 * Created by lxs.
 * 2020/5/22 6:25 PM
 */
public class TestBigObj {


    private static final int _1MB = 1024 * 1024;


    public static void main(String[] args) {
        byte[] obj;


        obj = new byte[7 * _1MB];
    }


}

次の図に示すように実行します。

上記のコードでは、作成されたオブジェクトが古い年齢に直接割り当てられています。3番目の赤いボックスを見てください。objオブジェクトは7MB、古い年齢は10MBで、79%を占めています。ただし、最初の2つの赤いボックスをもう一度見てみましょう。Eden領域はオブジェクトを割り当てませんが、メモリの一部を占有します。これは、仮想マシン自体がロードされるときに、独自の内部オブジェクトを持っている可能性があるため、この時点で、誰もが最初のコードを理解できるはずです。3つのオブジェクトの合計は7MBになります。Eden領域は収まるはずです。もちろんそうではありません。それに加えて、仮想マシン自体が占有するメモリもあります。マイナーGCをトリガーします。

最後に、一緒にやってみましょう。その前に、少しお話ししたいと思います。マイナーGC、メジャーGC、フルGCとよく耳にしますが、どういう意味ですか?実は新世代のGCです。これはマイナーGCと呼ばれ、旧世代のGCはメジャーGCと呼ばれます。フルGCは、若い世代と古い世代の両方がリサイクルされることを意味します。

ホットな推奨事項がありますか?

最も人気のあるJavaデータベースアクセスフレームワーク(DAOレイヤー)

今CとJavaを置き換えたい人はどうですか?

シングルスレッドのRedisが100万レベルのQPSを達成できるのはなぜですか?

乾物:クライアントの要求がサーバーに到達する方法を理解するためのテキスト

乾物共有:QRコードをスキャンして以下の公開アカウントをフォローし、バックグラウンド99 」に返信して、99セットの実際の戦闘プロジェクトと情報受け取ります

充電は、プロセスプログラマーのフラッシュ充電の宝に焦点を当てたい

記事が役に立ったら、それを読んで転送してください。

ご支援ありがとうございます(* ^ __ ^ *)

おすすめ

転載: blog.csdn.net/qq_17231297/article/details/106435892