Minor GC、Major GCとFull GCの違い(ネットワークに収集)

7998 ワード

Minor GC
若い世代空間(EdenとSurvivor領域を含む)からメモリを回収することをMinor GCと呼ぶ.この定義は明確で理解しやすい.しかし、Minor GC事件が発生した場合、いくつかの興味深い点に注意する必要があります.
JVMが新しいオブジェクトにスペースを割り当てることができない場合、例えばEden領域がいっぱいになった場合、Minor GCがトリガーされます.したがって、割当率が高いほど、Minor GCが頻繁に実行される.
メモリプールが満たされると、その内容はすべてコピーされ、ポインタは0から空きメモリを追跡します.EdenとSurvivor領域は、古典的なタグ、スキャン、圧縮、クリーンアップ操作に代わってタグとコピー操作を行った.したがって、EdenとSurvivor領域にはメモリフラグメントは存在しません.書き込みポインタは、使用するメモリプールの上部に常に留まっています.
Minor GC操作を実行しても、永続世代には影響しません.永続世代から若い世代への参照はGC rootsとされ、若い世代から永続世代への参照はタグ段階で直接無視される.
通常の認識を疑うと、すべてのMinor GCが「世界中の一時停止(stop-the-world)」をトリガーし、アプリケーションのスレッドを停止します.ほとんどのアプリケーションでは、停止による遅延は無視できます.その真相は、ほとんどのEden区の対象がゴミと見なされ、Survivor区や古い年代の空間にコピーされないことだ.逆に、Eden区の新入生の大部分がGCの条件を満たしていない場合、Minor GCの実行時に一時停止する時間が長くなります.
だからMinor GCの状況はかなり明らかです.Minor GCのたびに若い世代のメモリが整理されます.
Major GC vs Full GC
これらの用語はJVM仕様でもごみ収集研究論文でも正式に定義されていないことに注意してください.しかし、私たちが知っている限り、これらの定義が正しいことはよく知られています.Minor GCの若いテープメモリのクリーンアップは簡単に設計されるべきです.
Major GC 古い時代を整理するのです.
Full GC 若い世代と古い世代を含め、スタック全体を整理します.
残念なことに、実際には少し複雑で困惑しています.まず、多くのMajor GCはMinor GCによってトリガーされるので、この2つのGCを分離することは不可能な場合が多い.一方、多くの現代のごみ収集メカニズムは、永続的な空間の一部を整理するので、「cleaning」という言葉を使うのは部分的に正しいだけです.
これにより、Major GCと呼ぶのかFull GCと呼ぶのか、現在のGCがすべてのアプリケーションのスレッドを停止しているのか、アプリケーションのスレッドを停止することなく同時処理できるのかに注目する必要があります.
このような混乱はJVM標準ツールにも組み込まれている.次の例は私の意味をよく説明しています.2つの異なるツールConcurrent MarkとSweep collector(-X:+UseConcMarkSweepGC)がJVMで実行されたときに出力するトレース記録を比較してみましょう.
最初の試みは jstat 出力:
1 my-precious: me$ jstat -gc -t 4235 1s
1
2
3
4
5
6
7
8
9
10
11
12
13 Time S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT     5.7 34048.0 34048.0  0.0   34048.0 272640.0 194699.7 1756416.0   181419.9  18304.0 17865.1 2688.0 2497.6      3    0.275   0      0.000    0.275   6.7 34048.0 34048.0 34048.0  0.0   272640.0 247555.4 1756416.0   263447.9  18816.0 18123.3 2688.0 2523.1      4    0.359   0      0.000    0.359   7.7 34048.0 34048.0  0.0   34048.0 272640.0 257729.3 1756416.0   345109.8  19072.0 18396.6 2688.0 2550.3      5    0.451   0      0.000    0.451   8.7 34048.0 34048.0 34048.0 34048.0 272640.0 272640.0 1756416.0  444982.5  19456.0 18681.3 2816.0 2575.8      7    0.550   0      0.000    0.550   9.7 34048.0 34048.0 34046.7  0.0   272640.0 16777.0  1756416.0   587906.3  20096.0 19235.1 2944.0 2631.8      8    0.720   0      0.000    0.720 10.7 34048.0 34048.0  0.0   34046.2 272640.0 80171.6  1756416.0   664913.4  20352.0 19495.9 2944.0 2657.4      9    0.810   0      0.000    0.810 11.7 34048.0 34048.0 34048.0  0.0   272640.0 129480.8 1756416.0   745100.2  20608.0 19704.5 2944.0 2678.4     10    0.896   0      0.000    0.896 12.7 34048.0 34048.0  0.0   34046.6 272640.0 164070.7 1756416.0   822073.7  20992.0 19937.1 3072.0 2702.8     11    0.978   0      0.000    0.978 13.7 34048.0 34048.0 34048.0  0.0   272640.0 211949.9 1756416.0   897364.4  21248.0 20179.6 3072.0 2728.1     12    1.087   1      0.004    1.091 14.7 34048.0 34048.0  0.0   34047.1 272640.0 245801.5 1756416.0   597362.6  21504.0 20390.6 3072.0 2750.3     13    1.183   2      0.050    1.233 15.7 34048.0 34048.0  0.0   34048.0 272640.0 21474.1  1756416.0   757347.0  22012.0 20792.0 3200.0 2791.0     15    1.336   2      0.050    1.386 16.7 34048.0 34048.0 34047.0  0.0   272640.0 48378.0  1756416.0   838594.4  22268.0 21003.5 3200.0 2813.2     16    1.433   2      0.050    1.484
このセグメントは、JVM起動後17秒目に抽出されます.この情報に基づいて,12回のMinor GC,2回のFull GCを実行し,時間総スパンは50ミリ秒であった.に合格 jconsole または jvisualvm このようなGUIベースのツールは、同じ結果を得ることができます.
1 java -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC eu.plumbr.demo.GarbageProducer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 3.157: [GC (Allocation Failure) 3.157: [ParNew: 272640K->34048K(306688K), 0.0844702 secs] 272640K->69574K(2063104K), 0.0845560 secs] [Times: user=0.23 sys=0.03, real=0.09 secs] 4.092: [GC (Allocation Failure) 4.092: [ParNew: 306688K->34048K(306688K), 0.1013723 secs] 342214K->136584K(2063104K), 0.1014307 secs] [Times: user=0.25 sys=0.05, real=0.10 secs] ... cut for brevity ... 11.292: [GC (Allocation Failure) 11.292: [ParNew: 306686K->34048K(306688K), 0.0857219 secs] 971599K->779148K(2063104K), 0.0857875 secs] [Times: user=0.26 sys=0.04, real=0.09 secs] 12.140: [GC (Allocation Failure) 12.140: [ParNew: 306688K->34046K(306688K), 0.0821774 secs] 1051788K->856120K(2063104K), 0.0822400 secs] [Times: user=0.25 sys=0.03, real=0.08 secs] 12.989: [GC (Allocation Failure) 12.989: [ParNew: 306686K->34048K(306688K), 0.1086667 secs] 1128760K->931412K(2063104K), 0.1087416 secs] [Times: user=0.24 sys=0.04, real=0.11 secs] 13.098: [GC (CMS Initial Mark) [1 CMS-initial-mark: 897364K(1756416K)] 936667K(2063104K), 0.0041705 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 13.102: [CMS-concurrent-mark-start] 13.341: [CMS-concurrent-mark: 0.238 /0 .238 secs] [Times: user=0.36 sys=0.01, real=0.24 secs] 13.341: [CMS-concurrent-preclean-start] 13.350: [CMS-concurrent-preclean: 0.009 /0 .009 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 13.350: [CMS-concurrent-abortable-preclean-start] 13.878: [GC (Allocation Failure) 13.878: [ParNew: 306688K->34047K(306688K), 0.0960456 secs] 1204052K->1010638K(2063104K), 0.0961542 secs] [Times: user=0.29 sys=0.04, real=0.09 secs] 14.366: [CMS-concurrent-abortable-preclean: 0.917 /1 .016 secs] [Times: user=2.22 sys=0.07, real=1.01 secs] 14.366: [GC (CMS Final Remark) [YG occupancy: 182593 K (306688 K)]14.366: [Rescan (parallel) , 0.0291598 secs]14.395: [weak refs processing, 0.0000232 secs]14.395: [class unloading, 0.0117661 secs]14.407: [scrub symbol table, 0.0015323 secs]14.409: [scrub string table, 0.0003221 secs][1 CMS-remark: 976591K(1756416K)] 1159184K(2063104K), 0.0462010 secs] [Times: user=0.14 sys=0.00, real=0.05 secs] 14.412: [CMS-concurrent-sweep-start] 14.633: [CMS-concurrent-sweep: 0.221 /0 .221 secs] [Times: user=0.37 sys=0.00, real=0.22 secs] 14.633: [CMS-concurrent-reset-start] 14.636: [CMS-concurrent-reset: 0.002 /0 .002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
この結論にうなずく前に、同じJVMから収集を開始したゴミ収集ログの出力を見てみましょう.明らかに-XX:+PrintGCDetailsは、異なる詳細な物語を教えてくれます.
これらの情報に基づいて、Minor GCを12回見た後、上とは少し違います.フルGCは2回実行されていません.この違いは、単一GCが永続世代で異なるフェーズで2回実行されていることです.
最初のマーキングフェーズは,0.0041705秒,すなわち4 ms程度であった.この段階では「世界中( stop-the-world)」のイベントは、すべてのアプリケーションのスレッドを停止し、タグを開始します.
マークアップとクリーニングフェーズを並行して実行します.これらはすべてアプリケーションスレッドと並行しています.
最後のRemarkフェーズは、0.0462010秒で約46 msかかりました.この段階では再びすべてのイベントを一時停止します.
クリーンアップ操作を並行して実行します.名前の通り、このフェーズもパラレルであり、他のスレッドは停止しません.
だから、私たちがゴミ回収ログから見たように、実際にはMajor GCを実行して古い年代の空間を整理しただけで、Full GCを2回実行したわけではありません.
後期に決定を下すと、jstatから提供されたデータが正しい決定を導くことになります.すべてのイベントを停止する2つのイベントが正しくリストされているため、すべてのスレッドが合計50 ms停止しました.しかし、スループットを最適化しようとすると、誤解されます.リストには、初期タグの回収と最終Remarkフェーズのみがリストされており、jstatの出力には同時完了の作業は表示されません.
結論
このような状況を考慮して、Minor、Major、Full GCという方法で問題を考えるのは避けたほうがいい.アプリケーションの遅延またはスループットを監視し、GCイベントと結果を関連付ける必要があります.
これらのGCイベントが発生するにつれて、GCイベントがすべてのアプリケーション・スレッドに停止を強制したのか、一部のイベントを並列に処理したのか、追加の情報が必要になります.