JVM-オブジェクトメモリの割り当てと回収の詳細に関する質問


オブジェクトメモリの割り当てと回収の詳細に関する問題


1.システムを無効にする.gc()

System.gc():Full GCが直接トリガーされ、古い世代と新しい世代が回収されることが表示されます.一般的には、ゴミ回収時に自動的に行われ、手動でトリガーする必要はないと考えられています.頻繁なごみ回収はシステム性能に大きな影響を及ぼす.-XX:+DisableExplicitGCを使用すると、GCの表示が無効になり、System.gc()が空の関数に等価になります.

2. System.gc()使用同時回収


デフォルトでは、インスタントシステム.gc()が有効になり、従来のFull GC方式でスタック全体を回収し、パラメータが中断したUseG1GCUseConcMarkSweepGCを無視します.-XX:+ExplicitGCInvokesConcurrentを使用すると、System.gc()という表示GCは同時送信方式で回収されます.NOの場合、CMSとG 1が有効になっているかどうかにかかわらず、同時回収は行われません.

3.パラレルGC前に追加でトリガーされた新生代GC


合併回収器(UseParallelGCまたはUseParallelOldGCを使用)では、Full GCのたびに新生代のGCが伴います
従って、コンカレント回収器を使用する場合、System.gc()を使用すると2回のGCがトリガーされ、新生代を1回収集し、すべての回収作業を1回のFull GCに同時に渡すことを避けることで、1回の停止時間を短縮することができる.-XX:-ScavengeBeforeFullGCは、上記の特性を閉じることができ、デフォルトではtrueです.

4.対象がいつ古い時代に入るか


4.1老年対象者が老年期に入る


作成されたオブジェクトはeden領域に格納されます
オブジェクトがGCを通過するたびに、オブジェクトの年齢が1つ加算され、オブジェクトの年齢が一定の値に達すると、オブジェクトは古い世代のオブジェクトに昇格することができます.この値はMaxTenuringThresholdで設定でき、デフォルト値は15です.
package com.liuyao;

import java.util.HashMap;
import java.util.Map;

/**
 * Created By liuyao on 2018/4/18 15:56.
 */
public class MaxTenuringThreshold {
    public final static int _1M=1024*1024;
    public final static int _1K=1024;

    public static void main(String[] args) {
        Mapbyte[]> map=new HashMap<>();
        for (int i = 0; i < 5*_1K; i++) {
            byte[] bytes=new byte[_1K];
            map.put(i,bytes);
        }

        for (int i = 0; i < 17; i++) {
            for (int j = 0; j < 270; j++) {
                byte[] bytes=new byte[_1M];
            }
        }
    }
}

実行パラメータ:
-Xmx1024M -Xms1024M -XX:MaxTenuringThreshold=10 -XX:+UseSerialGC -XX:+PrintCommandLineFlags  -XX:+PrintGCDetails

実行パラメータを次のように変更します.
-Xmx1024M -Xms1024M -XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=15 -XX:+UseSerialGC  -XX:+PrintCommandLineFlags  -XX:+PrintGCDetails

MaxTenuringThresholdは対象昇進の十分な非必要条件であり、すなわちこの値に達すると、対象は必然的に昇進し、その年齢に達しないと、対象も昇進する可能性がある.実際,オブジェクトの実際の昇進年齢は,仮想マシンが実行時に自ら判断する.
オブジェクトの昇格を決定するもう1つの重要なパラメータは、survivor領域の目標使用率を設定するために使用されるTargetSurvivorRatioであり、デフォルトでは50である.すなわち、survivor領域がGCで50%を超えると、昇進年齢としてより小さなageが使用される可能性がある
以上、対象の実際の昇進年齢はsurvivor領域の使用状況に基づいて動的に計算され、MaxTenuringThresholdはこの年齢の最大値を表すだけである

4.2大対象が古い年代に入る


年齢のほかに、オブジェクトのボリュームもオブジェクトの昇進に影響します.オブジェクトが大きい場合、新生代がeden領域でもsurvivor領域でもオブジェクトを許容できない場合、オブジェクトは古い年代に直接割り当てられます.
PretenuerSizeThreshold:オブジェクトが古い世代に直接昇格するしきい値、単位値バイトを設定します.オブジェクトがこの値より大きい限り、新生代を迂回して古い世代に直接割り当てられます.このパラメータはParNewコレクタのみに対して有効であり、ParallelGCに対しては無効であり、この値のデフォルト値は0であり、この値のサイズを設定しないことを示し、すべては運転状況によって決まる.

5.TLABにオブジェクトを割り当てる


TLABはThread Local Allocation Bufferスレッドローカル割り当てキャッシュと呼ばれ、スレッド専用のメモリ割り当て領域である.オブジェクトの割り当てを加速させるために生成されます.
TLAB自体はeden領域の空間を占有し,TLABが有効な場合,仮想機会はJavaスレッドごとにTLAB空間を割り当てる.
TLABの空間は一般的にあまり大きくないため、大きいオブジェクトはTLABの上で割り当てることができなくて、いつも直接スタックの上で割り当てることができて、TLABは空間が小さいため、いつも詰めやすくて、もし1つの100 KBの空間ならば、もしすでに80 KBを使って、今1つの30 KBのオブジェクトを割り当てるならば、2つの方法があります:1.現在のTLABを廃棄すると、20 KBのスペースが無駄になる.この30 KBのオブジェクトをスタックに直接割り当て,今後20 KB未満のオブジェクトをTLABに割り当てることを望む.
仮想マシンの内部では、refill_wasteの値が維持されます.refill_wasteより大きいと、スタックに割り当てることが選択されます.この値より小さいと、現在のTLABが破棄され、新しいTLABが作成され、オブジェクトが割り当てられます.この値は-XX:TLABRefillWasteFractionによって設定することができ、これはTLABにおいてこのような浪費を許容する割合を表し、デフォルト値は64であり、すなわち約1/64のTLAB空間をrefill_として使用できることを示す.waste.
デフォルトではTLABとrefill_wasteはいずれも実行時に絶えず調整され、システムの実行を最適化します.-XX:+PrintTLAB:TLAB使用状況の表示-XX:-ResizeTLAB:TLABサイズの自動調整を無効にする-XX:TLABSize:手動でTLABサイズを指定する

6.方法finalize()のゴミ回収への影響


JavaはC++の構造関数のようなメカニズムを提供しています.finalize()関数です.
この関数を使用すると、オブジェクトの回収時にリソースの解放を行うためにサブクラスに再ロードできます.しかし、できるだけ使用しないでください.主な原因は次のとおりです.
  • finalize()は、オブジェクトを復活させる可能性があります
  • finalize()の実行時間は保障されておらず、完全にGCスレッドによって決定され、極端な場合、GCが発生しなければfinaliz()は実行する機会がありません.
  • 悪いfinalize()はGCの性能に深刻な影響を及ぼします.