本篇內容主要講解“CG管理和原理內容有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“CG管理和原理內容有哪些”吧!
成都創(chuàng)新互聯(lián)公司-專業(yè)網站定制、快速模板網站建設、高性價比黔西網站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式黔西網站制作公司更省心,省錢,快速模板網站建設找我們,業(yè)務覆蓋黔西地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。
GC: GC本身有三種語義,下文需要根據具體場景帶入不同的語義:
Garbage Collection :垃圾收集技術,名詞。
Garbage Collector :垃圾收集器,名詞。
Garbage Collecting :垃圾收集動作,動詞。
Mutator: 生產垃圾的角色,也就是我們的應用程序,垃圾制造者,通過 Allocator進行 allocate和 free。
TLAB: Thread Local Allocation Buffer的簡寫,基于CAS 的獨享線程(Mutator Threads)可以優(yōu)先將對象分配在 Eden 中的一塊內存,因為是 Java 線程獨享的內存區(qū)沒有鎖競爭,所以分配速度更快,每個 TLAB 都是一個線程獨享的。
Card Table: 中文翻譯為卡表,主要是用來標記卡頁的狀態(tài),每個卡表項對應一個卡頁。當卡頁中一個對象引用有寫操作時,寫屏障將會標記對象所在的卡表狀態(tài)改為 dirty,卡表的本質是用來解決跨代引用的問題。
從JCP(Java Community Process)的官網中可以看到,目前 Java 版本最新已經到了 Java 16,未來的 Java 17 以及現在的 Java 11 和 Java 8 是 LTS版本,JVM規(guī)范也在隨著迭代在變更,由于本文主要討論 CMS,此處還是放 Java 8 的內存結構。
GC 主要工作在 Heap 區(qū)和 MetaSpace 區(qū)(上圖藍色部分),在 Direct Memory 中,如果使用的是 DirectByteBuffer,那么在分配內存不夠時則是 GC 通過 Cleaner#clean 間接管理。(因為雖然內存分配和回收不歸JVM直接管理,但是引用還存放在JVM的heap中可以間接通過引用清除內存對象)
任何自動內存管理系統(tǒng)都會面臨的步驟:為新對象分配空間,然后收集垃圾對象空間,下面我們就展開介紹一下這些基礎知識。
Java中對象地址操作主要使用Unsafe調用了 C 的 allocate 和 free 兩個方法,分配方法有兩種:
空閑鏈表(free list): 通過額外的存儲記錄空閑的地址,將隨機 IO 變?yōu)轫樞?IO,但帶來了額外的空間消耗,此外還要增加O(1)級別的尋址時間。
碰撞指針(bump pointer): 通過一個指針作為分界點,需要分配內存時,僅需把指針往空閑的一端移動與對象大小相等的距離,分配效率較高,但使用場景有限。(必須規(guī)整的內存分配機制)
引用計數法(Reference Counting): 對每個對象的引用進行計數,每當有一個地方引用它時計數器 +1、引用失效則 -1,引用的計數放到對象頭中,大于 0 的對象被認為是存活對象。雖然循環(huán)引用的問題可通過 Recycler 算法解決,但是在多線程環(huán)境下,引用計數變更也要進行昂貴的同步操作,性能較低,早期的編程語言會采用此算法。
可達性分析,又稱引用鏈法(Tracing GC): 從 GC Root 開始進行對象搜索,可以被搜索到的對象即為可達對象,此時還不足以判斷對象是否存活/死亡,需要經過多次標記才能更加準確地確定,整個連通圖之外的對象便可以作為垃圾被回收掉。目前 Java 中主流的虛擬機均采用此算法。
自從有自動內存管理出現之時就有的一些收集算法,不同的收集器也是在不同場景下進行組合。
Mark-Sweep(標記-清除): 回收過程主要分為兩個階段,第一階段為追蹤(Tracing)階段,即從 GC Root 開始遍歷對象圖,并標記(Mark)所遇到的每個對象,第二階段為清除(Sweep)階段,即回收器檢查堆中每一個對象,并將所有未被標記的對象進行回收,整個過程不會發(fā)生對象移動。整個算法在不同的實現中會使用三色抽象(Tricolour Abstraction)、位圖標記(BitMap)等技術來提高算法的效率,存活對象較多時較高效。
Mark-Compact (標記-整理): 這個算法的主要目的就是解決在非移動式回收器中都會存在的碎片化問題,也分為兩個階段,第一階段與 Mark-Sweep 類似,第二階段則會對存活對象按照整理順序(Compaction Order)進行整理。主要實現有雙指針(Two-Finger)回收算法、滑動回收(Lisp2)算法和引線整理(Threaded Compaction)算法等。
Copying(復制): 將空間分為兩個大小相同的 From 和 To 兩個半區(qū),同一時間只會使用其中一個,每次進行回收時將一個半區(qū)的存活對象通過復制的方式轉移到另一個半區(qū)。有遞歸(Robert R. Fenichel 和 Jerome C. Yochelson 提出)和迭代(Cheney 提出)算法,以及解決了前兩者遞歸棧、緩存行等問題的近似優(yōu)先搜索算法。復制算法可以通過碰撞指針的方式進行快速地分配內存,但是也存在著空間利用率不高的缺點,另外就是存活對象比較大時復制的成本比較高。
把mark、sweep、compaction、copying這幾種動作的耗時放在一起看,大致有這樣的關系: 雖然 compaction 與 copying 都涉及移動對象,但取決于具體算法,compaction 可能要先計算一次對象的目標地址,然后修正指針,最后再移動對象。copying 則可以把這幾件事情合為一體來做,所以可以快一些。另外,還需要留意 GC 帶來的開銷不能只看 Collector 的耗時,還得看 Allocator。
如果能保證內存沒碎片,分配就可以用 pointer bumping 方式,只需要挪一個指針就完成了分配,非常快。而如果內存有碎片就得用 freelist 之類的方式管理,分配速度通常會慢一些。
ParNew:一款多線程的收集器,采用復制算法,主要工作在 Young 區(qū),可以通過-XX:ParallelGCThreads 參數來控制收集的線程數,整個過程都是STW的,常與CMS組合使用。
CMS: 以獲取最短回收停頓時間為目標,采用“標記-清除”算法,分 4 大步進行垃圾收集,其中初始標記和重新標記會 STW ,多數應用于互聯(lián)網站或者 B/S 系統(tǒng)的服務器端上,JDK9 被標記棄用,JDK14 被刪除,詳情可見 JEP 363。(性能和響應時間為優(yōu)先)
G1:一種服務器端的垃圾收集器,應用在多處理器和大容量內存環(huán)境中,在實現高吞吐量的同時,盡可能地滿足垃圾收集暫停時間的要求。
ZGC: JDK11 中推出的一款低延遲垃圾回收器,適用于大內存低延遲服務的內存管理和回收,SPECjbb 2015 基準測試,在 128G 的大堆下,最大停頓時間才 1.68 ms,停頓時間遠勝于 G1 和 CMS。
Shenandoah: 由 Red Hat 的一個團隊負責開發(fā),與 G1 類似,基于 Region 設計的垃圾收集器,但不需要 Remember Set 或者 Card Table 來記錄跨 Region 引用,停頓時間和堆的大小沒有任何關系。停頓時間與 ZGC 接近。
目前使用最多的是 CMS 和 G1 收集器,二者都有分代的概念,主要內存結構如下:
除此之外還有很多收集器,如 Metronome、Stopless、Staccato、Chicken、Clover 等實時回收器,Sapphire、Compressor、Pauseless 等并發(fā)復制/整理回收器,Doligez-Leroy-Conthier 等標記整理回收器。
延遲(Latency): 也可以理解為最大停頓時間,即垃圾收集過程中一次 STW 的最長時間,越短越好,一定程度上可以接受頻次的增大,GC 技術的主要發(fā)展方向。
吞吐量(Throughput): 應用系統(tǒng)的生命周期內,由于 GC 線程會占用 Mutator 當前可用的 CPU 時鐘周期,吞吐量即為 Mutator 有效花費的時間占系統(tǒng)總運行時間的百分比,例如系統(tǒng)運行了 100 min,GC 耗時 1 min,則系統(tǒng)吞吐量為 99%,吞吐量優(yōu)先的收集器可以接受較長的停頓。
目前各大互聯(lián)網公司的系統(tǒng)基本都更追求低延時,避免一次 GC 停頓的時間過長對用戶體驗造成損失,衡量指標需要結合一下應用服務的 SLA,主要如下兩點來判斷:
簡而言之,即為 一次停頓的時間不超過應用服務的 TP9999,GC 的吞吐量不小于 99.99% 。舉個例子,假設某個服務 A 的 TP9999 為 80 ms,平均GC停頓為30ms,那么該服務的最大停頓時間最好不要超過 80 ms,GC 頻次控制在 5 min 以上一次。
如果滿足不了,那就需要調優(yōu)或者通過更多資源來進行并聯(lián)冗余。(大家可以先停下來,看看監(jiān)控平臺上面的 gc.meantime分鐘級別指標,如果超過了 6 ms 那單機 GC 吞吐量就達不到4個9了。)
備注:除了這兩個指標之外還有 Footprint(資源量大小測量)、反應速度等指標,互聯(lián)網這種實時系統(tǒng)追求低延遲,而很多嵌入式系統(tǒng)則追求 Footprint。
System.gc(): 手動觸發(fā) GC 操作。
CMS: CMS GC 在執(zhí)行過程中的一些動作,重點關注 CMS Initial Mark 和 CMS Final Remark 兩個 STW 階段。
Promotion Failure: Old 區(qū)沒有足夠的空間分配給 Young 區(qū)晉升的對象(即使總可用內存足夠大)。
Concurrent Mode Failure: CMS GC 運行期間,Old 區(qū)預留的空間不足以分配給新的對象,此時收集器會發(fā)生退化,嚴重影響 GC 性能,下面的一個案例即為這種場景。
GCLocker Initiated GC: 如果線程執(zhí)行在 JNI 臨界區(qū)時,剛好需要進行 GC,此時 GC Locker 將會阻止 GC 的發(fā)生,同時阻止其他線程進入 JNI 臨界區(qū),直到最后一個線程退出臨界區(qū)時觸發(fā)一次 GC。
到此,相信大家對“CG管理和原理內容有哪些”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!