zoukankan      html  css  js  c++  java
  • CMS Collector and G1 Collector

    Understanding the CMS Collector

    CMS has three basic operations:

    • CMS collects the young generation (stopping all application threads).
    • CMS runs a concurrent cycle to clean data out of the old generation.
    • If necessary, CMS performs a full GC.

    concurrent cycle

    • The JVM starts a concurrent cycle based on the occupancy of the heap. When it is 
      sufficiently full, the JVM starts background threads that cycle through the heap and 
      remove objects.
    • The concurrent cycle starts with an initial mark phase, which stops all the application 
      threads.This phase is responsible for finding all the GC root objects in the heap.
    • The next phase is the mark phase, and it does not stop the application threads.Since it is just a 
      marking phase, it hasn’t done anything to the heap occupancy, and so no data is shown 
      about that.
    • Next comes a preclean phase, which also runs concurrently with the application threads:
    • The next phase is a remark phase, but it involves several operations:
    • Next comes another concurrent phase—the sweep phase:
    • Next comes the concurrent reset phase:

    concurrent mode failure:

    • When a young collection occurs and there isn’t enough room in the old generation to 
      hold all the objects that are expected to be promoted, CMS executes what is essentially 
      a full GC. All application threads are stopped, and the old generation is cleaned of any 
      dead objects, reducing its occupancy to 1,366 MB—an operation which kept the application 
      threads paused for a full 5.6 seconds. That operation is single-threaded, which is one reason it takes so long (and one reason why concurrent mode failures are worse as 
      the heap grows).
    • The second problem occurs when there is enough room in the old generation to hold 
      the promoted objects, but the free space is fragmented and so the promotion fails: 
      • As a result, in the middle of the young collection (when all threads were already stopped), 
        CMS collected and compacted the entire old generation. The good news is that 
        with the heap compacted, fragmentation issues have been solved (at least for a while). 
        But that came with a hefty 28-second pause time. This time is much longer than when 
        CMS had a concurrent mode failure because the entire heap was compacted; the concurrent 
        mode failure simply freed objects in the heap. The heap at this point appears as 
        it did at the end of the throughput collector’s full GC (Figure 6-2): the young generation 
        is completely empty, and the old generation has been compacted.
      • This occurs when permgen has filled up and needs to be collected; notice that the size 
        of the CMS Perm space has dropped. In Java 8, this can also occur if the metaspace needs 
        to be resized. By default, CMS does not collect permgen (or the metaspace), so if it fills 
        up, a full GC is needed to discard any unreferenced classes.

    summary

    • CMS has several GC operations, but the expected operations are 
      minor GCs and concurrent cycles.
    • Concurrent mode failures and promotion failures in CMS are 
      quite expensive; CMS should be tuned to avoid these as much as 
      possible.
    • By default, CMS does not collect permgen.

    Understanding the G1 Collector

    • G1 is a concurrent collector that operates on discrete regions within the heap. Each 
      region (there are by default around 2,048 of them) can belong to either the old or new 
      generation, and the generational regions need not be contiguous. The idea behind having 
      regions in the old generation is that when the concurrent background threads look 
      for unreferenced objects, some regions will contain more garbage than other regions. 
      The actual collection of a region still requires that application threads be stopped, but 
      G1 can focus on the regions that are mostly garbage and only spend a little bit of time 
      emptying those regions. This approach—clearing out only the mostly garbage regions 
      —is what gives G1 its name: Garbage First.
    • That doesn’t apply to the regions in the young generation: during a young GC, the entire 
      young generation is either freed or promoted (to a survivor space or to the old generation). 
      Still, the young generation is defined in terms of regions, in part because it makes 
      resizing the generations much easier if the regions are predefined. 
      G1 has four main operations: 
      • A young collection
      • A background, concurrent cycle
      • A mixed collection
      • If necessary, a full GC

    young collection

    • The G1 young collection is triggered when eden fills up (in this case, after filling four 
      regions). After the collection, there are no regions assigned to eden, since it is empty. 
      There is at least one region assigned to the survivor space (partially filled in this example), 
      and some data has moved into the old generation.
    • 23.430: [GC pause (young), 0.23094400 secs] 
      … 
      [Eden: 1286M(1286M)->0B(1212M) 
      Survivors: 78M->152M Heap: 1454M(4096M)->242M(4096M)] 
      [Times: user=0.85 sys=0.05, real=0.23 secs]
    • Collection of the young generation took 0.23 seconds of real time, during which the GC 
      threads consumed 0.85 seconds of CPU time. 1,286 MB of objects were moved out of 
      eden (which was resized to 1,212 MB); 74 MB of that was moved to the survivor space 
      (it increased in size from 78 M to 152 MB) and the rest were freed. We know they were 
      freed by observing that the total heap occupancy decreased by 1,212 MB. In the general 
      case, some objects from the survivor space might have been moved to the old generation, 
      and if the survivor space were full, some objects from eden would have been promoted 
      directly to the old generation—in those cases, the size of the old generation would 
      increase.

    concurrent G1 cycle

    • Finally, notice that the old generation (consisting of the regions marked with an O or 
      an X) is actually more occupied after the cycle has completed. That’s because the young 
      generation collections that occurred during the marking cycle promoted data into the old generation. In addition, the marking cycle doesn’t actually free any data in the old 
      generation: it merely identifies regions that are mostly garbage. Data from those regions 
      is freed in a later cycle.
    • The G1 concurrent cycle has several phases, some of which stop all application threads 
      and some of which do not. The first phase is an initial-mark phase. That phase stops all 
      application threads—partly because it also executes a young collection: 
      • As in a regular young collection, the application threads were stopped (for 0.28 seconds), 
        and the young generation was emptied (71 MB of data was moved from the young 
        generation to the old generation). The initial-mark output announces that the background 
        concurrent cycle has begun. Since the initial mark phase also requires all application 
        threads to be stopped, G1 takes advantage of the young GC cycle to do that 
        work. The impact of adding the initial mark phase to the young GC wasn’t that large: it 
        used 20% more CPU cycles than the previous collection, even though the pause was 
        only slightly longer. (Fortunately, there were spare CPU cycles on the machine for the 
        parallel G1 threads, or the pause would have been longer.)
    • Next, G1 scans the root region: 
      • 350.994: [GC pause (young) 
        351.093: [GC concurrent-root-region-scan-end, 0.6100090] 
        351.093: [GC concurrent-mark-start], 
        0.37559600 secs]
      • This takes 0.58 seconds, but it doesn’t stop the application threads; it only uses the 
        background threads. However, this phase cannot be interrupted by a young collection, 
        so having available CPU cycles for those background threads is crucial. If the young 
        generation happens to fill up during the root region scanning, the young collection 
        (which has stopped all the application threads) must wait for the root scanning to complete. 
        In effect, this means a longer-than-usual pause to collect the young generation.
      • The GC pause here starts before the end of the root region scanning, which (along with 
        the interleaved output) indicates that it was waiting. The timestamps show that application 
        threads waited about 100 ms—which is why the duration of the young GC pause 
        is about 100 ms longer than the average duration of other pauses in this log.
    • After the root region scanning, G1 enters a concurrent marking phase. This happens 
      completely in the background; a message is printed when it starts and ends: 
      • 111.382: [GC concurrent-mark-start] 
        …. 
        120.905: [GC concurrent-mark-end, 9.5225160 sec]
    • Concurrent marking can be interrupted, so young collections may occur during this 
      phase. The marking phase is followed by a remarking phase and a normal cleanup phase: 
      • 120.910: [GC remark 120.959: 
        [GC ref-PRC, 0.0000890 secs], 0.0718990 secs] 
        [Times: user=0.23 sys=0.01, real=0.08 secs] 
        120.985: [GC cleanup 3510M->3434M(4096M), 0.0111040 secs] 
        [Times: user=0.04 sys=0.00, real=0.01 secs]
    • These phases stop the application threads, though usually for a quite short time. Next 
      there is an additional cleanup phase that happens concurrently: 
      • 120.996: [GC concurrent-cleanup-start] 
        120.996: [GC concurrent-cleanup-end, 0.0004520]
    • And with that, the normal G1 cycle is complete—insofar as finding the garbage goes, at 
      least. But very little has actually been freed yet. A little memory was reclaimed in the 
      cleanup phase, but all G1 has really done at this point is to identify old regions that are 
      mostly garbage and can be reclaimed (the ones marked with an X in Figure 6-7).

    mixed GCs.

    • Now G1 executes a series of mixed GCs. They are called mixed because they perform 
      the normal young collection, but they also collect some number of the marked regions 
      from the background scan.
    • As is usual for a young collection, G1 has completely emptied eden and adjusted the 
      survivor spaces. Additionally, two of the marked regions have been collected. Those 
      regions were known to contain mostly garbage, and so a large part of them was freed. Any live data in those regions was moved to another region (just as live data was moved 
      from the young generation into regions in the old generation). This is why G1 ends up 
      with a fragmented heap less often than CMS—moving the objects like this is compacting 
      the heap as G1 goes along.
    • 79.826: [GC pause (mixed), 0.26161600 secs] 
      …. 
      [Eden: 1222M(1222M)->0B(1220M) 
      Survivors: 142M->144M Heap: 3200M(4096M)->1964M(4096M)] 
      [Times: user=1.01 sys=0.00, real=0.26 secs]
    • Notice that the entire heap usage has been reduced by more than just the 1,222 MB 
      removed from eden. That difference (16 MB) seems small, but remember that some of 
      the survivor space was promoted into the old generation at the same time; in addition, 
      each mixed GC cleans up only a portion of the targeted old generation regions. As we 
      continue, we’ll see that it is important to make sure that the mixed GCs clean up enough 
      memory to prevent future concurrent failures.
    • The mixed GC cycles will continue until (almost) all of the marked regions have been 
      collected, at which point G1 will resume regular young GC cycles. Eventually, G1 will 
      start another concurrent cycle to determine which regions should be freed next.

    full GC

    • As with CMS, there are times when you’ll observe a full GC in the log, which is an 
      indication that more tuning (including, possibly, more heap space) will benefit the application 
      performance. There are primarily four times when this is triggered:
    • Concurrent mode failure 
      • G1 starts a marking cycle, but the old generation fills up before the cycle is completed. 
        In that case, G1 aborts the marking cycle:
      • 51.408: [GC concurrent-mark-start] 
        65.473: [Full GC 4095M->1395M(4096M), 6.1963770 secs] 
        [Times: user=7.87 sys=0.00, real=6.20 secs] 
        71.669: [GC concurrent-mark-abort]
      • This failure means that heap size should be increased, or the G1 background processing 
        must begin sooner, or the cycle must be tuned to run more quickly (e.g., by 
        using additional background threads).
    • Promotion failure 
      • G1 has completed a marking cycle and has started performing mixed GCs to clean 
        up the old regions, but the old generation runs out of space before enough memory 
        can be reclaimed from the old generation. In the log, a full GC immediately follows 
        a mixed GC:
      • 2226.224: [GC pause (mixed) 
        2226.440: [SoftReference, 0 refs, 0.0000060 secs] 
        2226.441: [WeakReference, 0 refs, 0.0000020 secs] 
        2226.441: [FinalReference, 0 refs, 0.0000010 secs] 
        2226.441: [PhantomReference, 0 refs, 0.0000010 secs] 
        2226.441: [JNI Weak Reference, 0.0000030 secs] 
        (to-space exhausted), 0.2390040 secs] 
        …. 
        [Eden: 0.0B(400.0M)->0.0B(400.0M) 
        Survivors: 0.0B->0.0B Heap: 2006.4M(2048.0M)->2006.4M(2048.0M)] 
        [Times: user=1.70 sys=0.04, real=0.26 secs] 
        2226.510: [Full GC (Allocation Failure) 
        2227.519: [SoftReference, 4329 refs, 0.0005520 secs] 
        2227.520: [WeakReference, 12646 refs, 0.0010510 secs] 
        2227.521: [FinalReference, 7538 refs, 0.0005660 secs] 
        2227.521: [PhantomReference, 168 refs, 0.0000120 secs] 
        2227.521: [JNI Weak Reference, 0.0000020 secs] 
        2006M->907M(2048M), 4.1615450 secs] 
        [Times: user=6.76 sys=0.01, real=4.16 secs]
      • This failure means the mixed collections need to happen more quickly; each young 
        collection needs to process more regions in the old generation.
    • Evacuation failure 
      • When performing a young collection, there isn’t enough room in the survivor 
        spaces and the old generation to hold all the surviving objects. This appears in the 
        GC logs as a specific kind of young GC:
      • 60.238: [GC pause (young) (to-space overflow), 0.41546900 secs]
      • This is an indication that the heap is largely full or fragmented. G1 will attempt to 
        compensate for this, but you can expect this to end badly: G1 will resort to performing 
        a full GC. The easy way to overcome this is to increase the heap size,
    • Humongous allocation failure 
      • Applications that allocate very large objects can trigger another kind of full GC in 
        G1; see “G1 allocation of humongous objects” on page 169. There are no tools to 
        diagnose that situation specifically from the standard GC log, though if a full GC 
        occurs for no apparent reason, it is likely due to an issue with humongous allocations.

    Quick Summary

    • G1 has a number of cycles (and phases within the concurrent 
      cycle). A well-tuned JVM running G1 should only experience 
      young, mixed, and concurrent GC cycles.
    • Small pauses occur for some of the G1 concurrent phases.
    • G1 should be tuned if necessary to avoid full GC cycles.

  • 相关阅读:
    【翻译】ASP.NET Web API入门
    ASP.NET Web API 简介
    浅析利用MetaWeblog接口同步多个博客
    说说JSON和JSONP,也许你会豁然开朗
    说说JSON和JSONP,也许你会豁然开朗
    点击ListView 获取所选择行的数据
    Label 控件设置背景透明色
    C#遍历窗体所有控件或某类型所有控件 (转)
    使用Window 自带的控件 axWindowsMediaPlayer 制作播放器
    ASP.net 学习路线(详细)
  • 原文地址:https://www.cnblogs.com/parkdifferent/p/9691718.html
Copyright © 2011-2022 走看看