JVM的垃圾回收器詳解
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達
? 作者?|? gaohuan30
來源 |? urlify.cn/ji2mY3
經典垃圾收集器
如果說收集算法是內存回收的方法論,那垃圾收集器就是內存回收的實踐者。
這些經典的收集器盡管已經算不上是最先進的技術,但他們曾在實踐中千錘百煉,足夠成熟。

HotSpot虛擬機的垃圾收集器
圖中展示了其中作用于不同分代的收集器,如果兩個收集器之間存在連線,就說明它們可以搭配使用。圖中收集器所處的區(qū)域,則表示它是屬于新生代收集器抑或是老年代收集器。
ps:雖然垃圾收集器的技術在不斷進步,但直到現在還沒有最好的收集器出現,更加不存在"萬能"的收集器,所以我們選擇的只是對具體應用最合適的收集器。如果有一種放之四海而皆準、任何場景下都適用的完美收集器存在。HotSpot虛擬機完全沒必要實現那么多種不同的收集器了
Serial 收集器
Serial 收集器是最基礎、歷史最悠久的收集器,曾經(JDK 1.3.1之前)是HotSpot虛擬機新生代收集器的唯一選擇。從名字就可以猜出,這個收集器是一個**單線程**工作的收集器。但它的 "單線程"的意義并不僅僅是說明它只會使用一個處理器
或一條收集線程去完成垃圾收集工作,更重要的是強調它在進行垃圾收集時,必須暫停其他所有工作線程,直到它收集結束。"Stop The World" 這個詞語也許聽起來很酷,但這項工作是由*虛擬機在后臺自動發(fā)起和自動完成的*,這對很多應用來說都是不能接受
的,不妨試想一下,要是你的電腦每運行一小時就會暫停五分鐘,你會有什么心情?

Serial/Serial Old 收集器運行示意圖
雖然 Serial 收集器最早出現,但目前已經老而無用,食之無味,棄之可惜的"雞肋",但事實上,它仍然時HotSpot虛擬機運行在客戶端模式下的默認新生代收集器有著優(yōu)于其他收集器的地方,那就是簡單而高效,對于內存資源受限的環(huán)境,他是所有收集器里
額外內存消耗最小的;對于單核處理器或處理器核心數較少的環(huán)境來說,Serial收集器由于沒有線程交互的開銷,專心做垃圾收集器自然可以獲得最高的單線程收集效率。在用戶桌面的應用場景以及近年來流行的部分微服務應用中,分配給虛擬機管理的內存一般來說
并不會特別大,收集幾十兆甚至一二百兆的新生代,垃圾收集器的停頓時間完全可以控制在十幾,幾十毫秒,最多一百多毫秒以內,只要不是頻繁發(fā)生收集,這點停頓時間對許多用戶來說完全是可以接受的。
ParNew 收集器
ParNew 收集器實質上時Serial收集器的多線程并行版本,除了同時使用多條線程進行垃圾收集之外,其余的行為包括 Serial收集器可用的所有控制參數(例如 -XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法
Stop The World、對象分配規(guī)則、回收策略等都完全一致。

ParNew/Serial Old收集器運行示意圖
ParNew 收集器除了支持多線程并行收集之外,其他于Serial收集器相比并沒有太多創(chuàng)新之處,但它確實不少運行在服務端模式下的HotSpot虛擬機,時JDK 7 之前遺留系統(tǒng)首選的新生代收集器,其中有一個與功能、性能無關但其實
很重要的原因是:除了Serial收集器外,目前只有它能與CMS收集器配合工作
ps:JDK 9 開始,ParNew加CMS收集器的組合就不再是官方推薦的服務端模式下的收集器解決方案了。官方細外它能夠完全被 G1 所取代甚至還取消了ParNew 加 Serial Old 以及 Serial 加 CMS 這兩組收集器組合的支持。
也可以理解為ParNew 合并入CMS成為它專門處理新生代的組成部分。
-XX:ParallelGCThreads 參數來限制垃圾收集的線程數
Parallel Scavenge 收集器
Parallel Scavenge 收集器也是一款新生代收集器,它同樣是基于標記-復制算法實現的收集器,也是能夠并行收集的多線程收集器。
Parallel Scavenge 收集器的特點是它的關注點與其他收集器不同,CMS 等收集器的關注點是盡可能地縮短垃圾收集時用戶線程地停頓時間,而PS 收集器地目標則時達到一個可控地吞吐量(Throughput)。所謂吞吐量就是處理器用于運行用戶代碼的時
間與處理器總消耗時間地比值 即 吞吐量 = (運行用戶代碼時間)/(運行用戶代碼時間 + 運行垃圾收集時間)
如果虛擬機完成某個任務,用戶代碼加垃圾收集總耗費了100分鐘,其中垃圾收集花掉 1 分鐘,那吞吐量就是 99% 。停頓時間越短就越適合需要與用戶交互或需要保證服務響應質量的程序,良好的響應速度能提高用戶體驗;而高吞吐量則可以最高效率
地利用處理器資源,盡快完成程序地運算任務。主要適合在后臺運算而不需要太多交互地分析任務。
Paraller Scavenge 收集器提供了兩個參數用于精確控制吞吐量,分別是控制最大垃圾收集停頓時間的 -XX:MaxGCPauseMillis 參數以及直接設置吞吐量大小的 -XX:GCTimeRatio參數
1.-XX:MaxGCPauseMillis 參數允許的值是一個大于0的毫秒數,收集器將盡力保證內存回收花費的時間不超過用戶設置值。不過不要異想天開的認為如果把這個參數值設置的更小就可以使得系統(tǒng)垃圾收集速度變得更快,垃圾收集停頓時間
是以犧牲吞吐量和新生代空間為代價換取的。
2.-XX:GCTimeRatio 參數的值應時一個大于0 小于100 的整數,也就是垃圾收集時間占總時間的比率,相當于吞吐量的倒數。譬如把此參數設置為 19 ,那允許的最大垃圾收集時間就占總時間的 5 % (即 1/(1+19)),默認值為99。
即允許最大 1%(1/(1+99)) 的垃圾收集時間。
3.Parallel Scavenge 收集器也經常被稱作"吞吐量優(yōu)先收集器",還有一個參數 -XX:UseAdaptiveSizePolicy 這是一個開關參數,激活之后就不需要人工指定新生代的大小(-Xmn)、Eden 與Survivor區(qū)的比例(-XX:SurvivorRatio)、
晉升老年代對象大小(-XX:PretenureSizeThreshold)等細節(jié)參數了。虛擬機會根據當前系統(tǒng)的運行情況收集性能監(jiān)控信息、動態(tài)調整這些參數以提供最合適的停頓時間或者最大的吞吐量。這種調節(jié)方式稱為垃圾手機的自適應調節(jié)策略(GC Ergonomics)。
只需要把基本的內存數據設置號(-Xmx最大堆)然后使用1,2 參數給虛擬機設置一個優(yōu)化目標,那具體細節(jié)參數調節(jié)工作就有虛擬機完成。自適應調節(jié)也是 Parallel Scavenge收集器區(qū)別于 ParNew 收集器的一個重要特征。
Serial Old 收集器
Serial Old 時Serial收集器的老年代版本,它同樣是一個單線程收集器,color="red">使用標記-整理算法。
這個收集器的主要意義也是共客戶端模式下的HotSpot虛擬機使用,
如果在服務端模式下,它也可能有兩種用途:
1.在JDK 5 以及以前的版本種與 Parallel Scavenge收集器搭配使用。
2.作為 CMS 收集器發(fā)生失敗時的后備預案,在并發(fā)收集發(fā)生 Concurrent Mode Failure時使用。
Parallel Old 收集器
Parallel Old 時Parallel Scavenge 收集器的老年代版本,支持多線程并發(fā)收集,基于 **標記-整理算法** 實現。這個收集器時直到 JDK 6 時才開始提供的,"吞吐量優(yōu)先"收集器終于有了比較名副其實的搭配組合。
CMS 收集器
簡述及運行過程
CMS (Concurrent Mark Sweep)收集器是一種 **以獲取最短回收停頓時間** 為目標的收集器。非常適用于關注服務的響應時間,細外系統(tǒng)停頓時間盡可能短,以給用戶帶來很好的交互。
基于 **標記-清除** 算法實現 整體過程分為四個步驟包括
1.初始標記(CMS initial mark) (STW) 僅僅只是標記一下GC Roots能直接關聯(lián)到的對象,速度很快
2.并發(fā)標記(CMS concurrent mark) 從直接關聯(lián)對象開始遍歷整個對象圖的過程,耗時較長但是不需要停頓用戶線程
3.重新標記(CMS remark) (STW)是為了修正并發(fā)標記期間,因用戶線程繼續(xù)運行而導致標記產生的那一部分對象的標記記錄
4.并發(fā)清除(CMS concurrent sweep) 清理刪除標記階段判斷的已經死亡的對象

CMS 收集器運行示意圖
CMS 優(yōu)點及其缺點
優(yōu)點
CMS 是一款優(yōu)秀的收集器,它最主要的優(yōu)點在名字上已經體現出來:**并發(fā)收集、低停頓**
缺點
CMS 收集器時HotSpot虛擬機追求低停頓的第一次成功嘗試,但是它還遠達不到完美的程度,至少有以下三個明顯的缺點:
CMS 對處理器資源非常敏感
事實上,面向并發(fā)設計的程序都對處理器資源比較敏感,在并發(fā)階段它雖然不會導致用戶線程停頓,但卻會因為占用了一部分線程而導致應用程序變慢,降低總吞吐量。CMS 默認啟動的回收線程數是(處理器核心數量+3)/4,也就是說,如果處理器核心數
在四個或以上,并發(fā)回收時垃圾收集線程只不過占用不超過25% 的處理器運算資源,并且會隨處理器核心數量的增加而下降。但當處理器核心數量不足四個時,CMS 對用戶程序的影響就肯恩變得很大。未來緩解這種情況,虛擬機提供了一種稱為“增量式并
發(fā)收集器”的CMS收集器變種,在并發(fā)標記、清理的時候讓收集器線程、用戶線程交替運行,盡量減少垃圾收集線程的獨占資源的時間。JDK 7 i-CMS模式已經被聲明為"deprecated" JDK 9 被完全廢棄
CMS 無法處理"浮動垃圾" 及 需要注意 CMS觸發(fā)時間以及發(fā)生"并發(fā)失敗"
在CMS 的并發(fā)標記和并發(fā)清理階段,用戶線程還在繼續(xù)運行的,程序在運行過程自然就還會伴隨有新的垃圾對象不斷產生,但這一部分垃圾對象是出現在標記過程結束以后,CMS 無法在當此收集種處理掉它們,只要留待下一次垃圾收集時再清理掉。
這一部分垃圾就稱為"浮動垃圾"。同樣也是由于在垃圾收集階段用戶線程還需要持續(xù)運行,那就還需要預留足夠內存空間提供給用戶線程使用,因此 CMS 收集器不能像其他收集器那樣等待到老年代幾乎完全被填滿在進行收集,必須預留一部分空間供并發(fā)
收集時的程序運作使用。
JDK 5 的默認設置下,當老年代使用 68% 的空間后就會被激活。可以適當調用參數 -XX:CMSInitiatingOccu-pancyFraction 的值提高 CMS 出發(fā)百分比降低內存回收頻率,獲取更好的性能,到JDK 6時 CMS 啟動閾值已經默認提升至 92% ,但
這又會更容易面臨另一種風險,要是 CMS 運行期間預留的內存無法滿足程序分配新對象的需要,就會出現一次 "并發(fā)失敗"(Concurrent Mode Failure)這時候虛擬機將不得不啟動后備預案:凍結用戶線程的執(zhí)行,臨時啟用Serial Old 收集器來重新進行
老年代的垃圾收集,但這樣停頓時間就很長了,所有上述參數設置太大將會很容易導致大量的并發(fā)失敗產生,性能反而降低。
采用"標記-清除"算法造成空間碎片過多 造成大對象分配問題
使用該算法意味著手機結束時會有大量空間碎片產生??臻g碎片過多時,將會給大對象分配帶來很大麻煩,往往會出現老年代還有很多剩余空間,但就是無法找到足夠大的連續(xù)空間來分配當前對象,而不得不提前觸發(fā)一次 Full FC 的情況。為了解決
這個問題,CMS 收集器提供了一個 -XX:UseCMSCompactAtFullCollection 開關參數(默認開始 JDK9 開始廢棄),用于在CMS收集器不得不進行Full GC時開啟內存碎片的合并整理過程,由于內存整理必須移動存活對象,是無法并發(fā)的。這樣空間碎片的問
題是解決了但停頓時間又會變長,因此還有一個參數 -XX:CMSFullGCsBeforeCompaction(默認值為0,每次進入Full GC 都進行碎片整理 ,JDK9 開始廢棄),參數要求CMS收集器在執(zhí)行若干次不整理空間的 Full GC后,下一次進入FullGC就會先進行碎
片整理。
Garbage First 收集器
簡述
Garbage First(簡稱G1)收集器時垃圾收集器技術發(fā)展歷史上里程碑式的成果,它開創(chuàng)了收集器面向局部收集的設計思路和基于Region的內存布局形態(tài),JDK 8 Update 40 的時候,G1提供并發(fā)的類卸載的支持,補全了其計劃功能的最后一塊拼圖。
這個版本的 G1 收集器才被Oracle 官方稱為"全功能的垃圾收集器"(Full-Featured Garbage Collector)。
G1 是一款主要面向**服務端應用**的垃圾收集器。JDK 9 發(fā)布之日,G1宣告取代Parallel Scavenge加Parallel Old 組合,成為服務端模式下的默認垃圾收集器,而CMS 則淪落至被聲明偉不推薦使用(Deprecate)的收集器。
運行過程
1.初始標記: 僅僅只是標記一下GC Roots能直接關聯(lián)到的對象,并且修改TAMS指針的值,讓下一階段用戶線程并發(fā)運行時,能正確地在可以用Region中分配新對象。這一階段需要停頓線程,但耗時很短,而且是借用進行Minor GC的時候同步完成的,
所有G1 收集器在這個階段實際并沒有額外的停頓
2.并發(fā)標記: 從GC Roots開始對堆中對象進行可達性分析,遞歸掃描整個堆里的對象圖,找到要回收的對象,這階段耗時較長,但可與用戶程序并發(fā)執(zhí)行。當對象圖掃描完成以后,還要重新處理SATB記錄下的在并發(fā)時有引用變動的對象。
3.最終標記: 對用戶線程做另一個短暫的暫停,用于處理并發(fā)階段結束后仍遺留下來的最后那少量的SATB記錄。
4.篩選回收: 負責更新Region的統(tǒng)計數據,對各個Region的回收價值和成本進行排序,根據用戶所期望的停頓時間來指定回收計劃,可以自由選擇任意多個Region構成會收集,然后把決定回收的那一部分Region的存活對象復制到空的Region中,再
清理掉整個舊Region的全部空間。這里的操作涉及存活對象的移動,時必須暫停用戶線程,由多條收集器線程并行完成的。
G1 收集器運行示意圖
停頓時間模型
作為CMS收集器的替代者和繼承人,設計者們希望做出一款能夠建立起"停頓時間模型"(Pause Prediction Mdel)的收集器,停頓時間模型的意思時能夠支持指定在一個長度為 M毫秒的時間片段內,消耗在垃圾收集上的時間大概率不超過N毫秒這樣
的目標。那具體如何實現這個目標呢?首先要有一個思想上的改變,在G1 收集器出現之前的所有收集器,包括CMS在內,垃圾收集器的目標范圍要么是整個新生代(Minor GC),要么就是整個老年代(Major GC),在要么就是整個Java堆(Full GC)。而G1跳出
這個樊籠,它可以面向堆內存任何部分來組成會收集(Collection Set 一般簡稱CSet)進行回收。衡量標準不再是它屬于哪個分代,而是哪塊內存中存放的垃圾數量最多,回收收益最大,這就是G1收集器的Mixed GC模式。
Region
G1 開創(chuàng)了基于Region 的堆內存布局是它能夠實現這一目標的關鍵。雖然G1也仍遵循分代收集理論設計的。但其堆內存的布局與其他收集器有非常明顯的差異:G1不再堅持固定大小以及固定數量的分代區(qū)域劃分,而是把連續(xù)額Java堆劃分為多個大小
相等的獨立區(qū)域(Region),每個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。收集器能夠對扮演不同角色的Region采用不同的策略去處理,這樣無論是新創(chuàng)建的對象還是以及存活了一段時間、熬過多次收集的就對象>
都能獲取很好的收集效果。
Humongous(存儲大對象)
Region中還有一類特殊的Humongous區(qū)域,專門用來存儲大對象。G1認為只要大小超過一個Region容量的一半的對象即可判斷為大對象。每個Region的大小可以通過參數 -XX:G1HeapRegionSize設置,取值范圍為1MB~32MB,且應為2的N次冪。
而面對那些超過整個Region容量的超級大對象,將會被存放在N個連續(xù)的HumongousRegion之中,G1中大多數行為都把Humongous Region作為老年代的一部分看待。

G1收集器Region示意圖
-XX:MaxGcPauseMillis
G1雖然任然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它們都是一系列區(qū)域的動態(tài)集合。G1收集器之所以能建立可預測的停頓時間模型,是因為它將Region作為單次回收的最小單元,即每次收集到的內存空間都是Region大小的
整數倍,這樣可以有計劃地避免在整個Java堆中盡心全區(qū)域的垃圾收集。更具體的處理思路是讓G1收集器去跟蹤各個Region里面的垃圾堆積的"價值"大小,價值即回收所獲得的空間大小以及回收所需時間的經驗值,然后在后臺維護一個優(yōu)先級列表,每次根據
用戶設置的允許的收集停頓時間(參數-XX:MaxGCPauseMillis指定,默認200毫秒),優(yōu)先處理回收價值收益最大的那些Region,也就是"Garbage First"名字的由來。---這種使用Region劃分內存空間,以及具有優(yōu)先級的區(qū)域回收方式,保證了G1收集器在
有限時間內獲取盡可能高的收集效率。
G1 潛在問題
如何解決多Region存在的跨Region引用
解決思路使用 [記憶集](https://www.cnblogs.com/huan30/p/14323091.html) 避免全堆作為 GC Roots掃描,在G1收集器上記憶集的應用其實要復雜很多,它的每個Region都維護有自己的記憶集,這些記憶集會記錄下別的Region指向自己的
指針并標記這些指針分別在那些卡頁的范圍之內。
G1的記憶集在存儲結構的本質上是一種哈希表,Key是別的Region的起始地址,Value是一個集合,理論存儲的元素是卡表的索引號。這種"雙向"的卡表結構(卡表是"我指向誰",這種結構還記錄著"誰指向我")比原來的卡表實現起來更復雜,同時由于Region
數量比傳統(tǒng)收集器的分代數量明顯要多得多,因此G1收集器要比其他傳統(tǒng)垃圾收集器有著更高的內存占用負擔。根據經驗,G1至少要消耗大約相當于Java堆容量10%至20%的額外內存來維持收集器工作
并發(fā)標記階段如何保證收集線程與用戶線程互不干擾
這里首先要解決的是用戶線程改變對象引用關系時,必須保證其不能打破原本的對象圖結構:CMS 收集器次啊用增量更新算法實現,而G1收集器則是通過原始快照(STAB)算法來實現。此外,垃圾收集堆用戶線程的影響還體現在回收過程中新創(chuàng)建對象的
內存分配上,程序要繼續(xù)運行就肯定會持續(xù)有新對象被創(chuàng)建,G1為每一個Region涉及了兩個名為TAMS(Top at Mark Start)的指針,把Region中的一部分空間劃分出來用于并發(fā)回收過程中新對象分配,并發(fā)回收時新分配的對象地址都必須要在這兩個指針位置
以上。G1收集器默認在這個地址上的對象是被隱式標記過的,即默認它們是存活的,不納入回收范圍。與CMS中"Concurrent Mode Failure"失敗會導致Full GC 類似,如果內存回收的速度趕不上內存分配的速度,G1收集器也要被迫凍結用戶線程執(zhí)行,導致
Full GC而產生長時間"Stop The World"
怎么建立起可靠的停頓預測模型
用戶通過-XX:MaxGCPauseMillis參數指定的停頓時間只意味著垃圾收集發(fā)生之前的期望值,但G1收集器要怎么做才能滿足用戶的期望呢?G1收集器的停頓預測模型是以衰減均值(Decaying Average)為理論基礎來實現的,在垃圾收集過程中,G1收集器
會記錄每個Region的回收耗時、每個Region記憶集里的臟卡數量等各個可測量的步驟花費的成本,并分析得出平均值、標準偏差、置信度等統(tǒng)計信息。話句話說,Region的統(tǒng)計狀態(tài)越新越能決定其回收的價值。然后通過這些信息預測現在開始回收的話,有哪些
Region組成的回收集才可以在不超過期望停頓時間的約束下獲得最高的收益。
G1 對比 CMS
優(yōu)點
指定最大停頓時間、分Region的內存布局、按收益動態(tài)確定回收集
G1 整體采用 "標記-整理" 算法實現,運行期間不會產生內存空間碎片。垃圾收集完成之后能提供規(guī)整的可用內存。有利于程序長時間運行,在程序為大對象分配內存時不容易因無法找到連續(xù)內存空間而提前出發(fā)下一次收集
缺點
G1無論是為了垃圾收集產生的內存占用還是程序運行的額外執(zhí)行負載都要比CMS要高
內存占用
G1 和 CMS 都是用卡表來處理跨代指針,但G1的卡表實現更為復雜,而且堆中每個Region,無論扮演老年代還是新生代,都必須有一份卡表,這導致G1的記憶集可能會占用整個堆容量的20%乃至更多的內存空間;相比起來CMS的卡表就相當簡單,只有唯一一份。
而且只需要處理老年代到新生代的引用,反過來則不需要。
執(zhí)行負載
由于兩個收集器各自的細節(jié)實現特點導致了用戶程序運行時的負載會有不同,譬如:
它們都是用到了寫屏障,CMS用寫后屏障來更新維護卡表;而G1除了使用寫后屏障來進行同樣的卡表維護操作外,為了實現原始快照搜索算法,還需要使用寫前屏障來跟蹤并發(fā)時的指針變化情況。
低延遲垃圾收集器
衡量垃圾收集器的三項最重要的指標是:內存占用(Footprint)、吞吐量(Throughput)和延遲(Latency),三者最多可以同時達成其中的兩項。
Shenandoah 收集器
相比G1 的改進
1.支持并發(fā)的整理算法
2.沒有使用分代收集
3.使用"連接矩陣"來記錄跨Region的引用關系
運行過程九階段
初始標記: 首先標記與GC Root是直接關聯(lián)的對象
并發(fā)標記: 遍歷對象圖,標記出全部可達的對象
最終標記: 處理剩余SATB掃描,并在這個階段統(tǒng)計回收價值最高的Region,構成一組回收集
并發(fā)清理: 用于清理那些整個區(qū)域內連一個存活對象都沒有找到的Region
并發(fā)回收: 將回收集里面的存活對象復制一份到其他未被使用的Region中。使用讀屏障和轉發(fā)指針應對并發(fā)問題
初始引用更新: 并發(fā)回收結束后把堆中所有指向舊對象的引用修正到復制后的新地址。實際并未做什么,只是為了建立一個線程集合點確保上步任務完成
并發(fā)引用更新: 真正開始進行引用更新操作。
最終引用更新: 修正GC Roots中的引用
并發(fā)清理: 整個回收集中所有Region再無存活對象,直接清空以便之后使用
Brooks Pointer 實現對象移動與用戶程序并發(fā)的一種解決方案
ZGC 收集器
特點
內存布局
ZGC的Region具有動態(tài)性---動態(tài)創(chuàng)建和銷毀,以及動態(tài)的區(qū)域容量大小。
小型Region: 容量固定為2MB,用于放置小于256KB的小對象
中型Region: 容量固定32MB,用于放置大于等于256KB但小于4MB的對象
大型Region: 容量不固定,可以動態(tài)變化,但必須是2MB的整數倍,用于放置4MB或以上的大對象。每個大型Region中只會存放一個大對象。因為復制一個大對象的代價非常高昂,所有不會被重分配,
并發(fā)整理算法的實現
染色指針
染色指針
運行過程
并發(fā)標記: ZGC的標記是在指針上而不是在對象上進行的,標記階段會更新染色指針中的Marked 0、Marked 1 標志位。
并發(fā)預備重分配: 這個階段需要根據特定的查詢條件統(tǒng)計得出本次收集過程中要清理那些Region將這些Region組成重分配集。
并發(fā)重分配: 把重分配集中的存活對象復制到新的Region上,并為重分配集中的每個Region維護一個轉發(fā)表,記錄從就對象到新對象的轉向關系。
并發(fā)重映射: 修正整個堆中指向重分配集中舊對象的所有引用。
鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布
??????
??長按上方微信二維碼?2 秒
感謝點贊支持下哈?
評論
圖片
表情
