很精彩的一次內部分享,介紹了大部分的GC演算法理論知識,JVM博大精深,本篇文章只是結合本次內部分享總結的一些理論知識,如果有大佬有疑問,歡迎留言指出! Concurrent:併發,程式一邊運行一邊做GC Parallel:並行,一塊區域,一個人做清掃,需要100s,但是把區域分成兩塊,用兩個人掃,時 ...
很精彩的一次內部分享,介紹了大部分的GC演算法理論知識,JVM博大精深,本篇文章只是結合本次內部分享總結的一些理論知識,如果有大佬有疑問,歡迎留言指出!
Concurrent:併發,程式一邊運行一邊做GC
Parallel:並行,一塊區域,一個人做清掃,需要100s,但是把區域分成兩塊,用兩個人掃,時間就縮短了一半;所以GC演算法有並行的,有不是並行的,這些都是可以根據自己的實際業務去選擇的,只有最適合自己的GC演算法;
Stop The World:簡稱STW,某些GC演算法當中,當需要做GC的時候,程式是必須停下來的,程式就是一個終止狀態,當GC結束之後再恢復;Java的GC很多時候都是STW,舉一個簡單的慄子,一邊掃地一邊嗑瓜子,這樣的話是永遠掃不幹凈的,記憶體的使用率就不是很高,當然STW有一個很大的缺點,就是程式必須終止,如果說做一次GC用時太長,需要十幾秒或者一分鐘或更多,那肯定是無法忍受的,這就需要GC調優來完成,通過演算法把時間控制在最短,讓用戶無感知;
root set:公集合,GC的時候會確定現在哪些對象還是存活的,
Generation GC:分代GC,先說一代GC,比方說現在有一個2G的記憶體區域,那麼需要GC的時候,需要把整塊記憶體區域2G遍歷一次,來做GC,這是一個很複雜的過程,需要判斷這麼多的對象是否引用或者被引用,可想而知耗時肯定會很長;以老王的經驗,1G記憶體做一次full GC停頓時間在1-3s,100G記憶體做一次full GC,停頓時間在1-3min,也就是說這幾分鐘程式什麼都幹不了,肯定是無法接受的;所以產出了分代GC,把一個區域分成幾個部分,年輕代1,年輕代2,和年老代。比方說程式開始運行,新產生的對象放在年輕代1,裝滿之後,結合copy演算法,從root節點出發,可能真正存活的對象只有很少一部分,那麼我們只把這部分對象拷貝到年輕代2裡面,然後將年輕代1區域全部清掃掉,這個copy演算法非常高效,但前提是需要程式的對象大部分都是用完一次就可以扔掉的,不然的話,存活的對象太多了,copy演算法就變得很低效了;所以copy演算法的效率取決於剩餘的對象,剩餘的對象越多,效率越低,剩餘的對象越少,效率越高;
RefCount:引用計數演算法,當有指針指向這個對象的時候,就把計數器+1,當不指向這個對象的時候把計數器-1,當這個對象的計數器為0的時候,這個對象的記憶體就可以釋放掉了,Python就是用的這個演算法,官方的python流派就是用的這個演算法,微軟的com組建結構也是用的這個引用計數演算法;這個演算法兩個缺點:效率低,因為訪問對象是一個很頻繁的操作,這樣頻繁做++;掃不幹凈,迴圈列表,a->b->c,其實外部沒有引用,但是內部有互相引用,其實abc都是垃圾;
MarkSweep:標記清除演算法,有很多對象,從公集合出發找其他的對象,是活的對象就做標記,標記的過程中,程式是不能跑的,當標記完了之後,沒有被標記的對象,就都可以釋放掉了,但是清掃之後的記憶體區域會變得千瘡百孔,再分配記憶體的時候,需要在這些記憶體中,找一個合適自己的記憶體區域;
MarkCompact:標記壓縮演算法,可以理解是標記清除演算法的一個升級版,同樣是在活對象上標記,但是它會選一個活對象作為一個端,把另外標記的活對象往這一端擠,這樣被釋放的區域就會是一大塊的;
Safepoint:當代碼運行到某個點,這個點可以做GC,這個點就叫safepoint,做GC的時候,所有的線程都需要停下來,就是所有的線程需要跑到這個安全點,跑到這個點的時候,Java虛擬機會生成一條指令,這個指令會讓這個線程訪問一個記憶體地址,這也是為了快速響應;因為線程停下來做別的事情非常耗性能;
Reference:強引用,強引用是我只要引用你,你就不會被垃圾回收;當然還有WeakReference弱引用和軟引用SoftReference等;
Java虛擬機的幾個GC演算法:
年輕代:Serial:串列,STW特性
ParNew:多線程,也是STW
ParScavenge:多線程,同樣是STW,是ParNew升級版
年老代:CMS:試圖平衡停頓時間,這個演算法的過程為:InitialMark->CCMark->Remark->CCSweep
SerialOld:MarkCompact演算法上面提到過的
ParOld:同樣是MarkCompact演算法,是SerialOld升級版
年輕代和年老代GC演算法是可以組合的,除了部分;
ZGC:Java11版本發佈推出,管理TB級記憶體,GC時間控制在10ms;