垃圾回收機制之GC-簡書

? ? ? ?線上服務(wù)器因為內(nèi)存溢出導(dǎo)致服務(wù)器假死,部分請求通過nginx轉(zhuǎn)發(fā)到這臺機時訪問報錯,在排查生產(chǎn)問題時順藤摸瓜的就找到了GC回收的問題,下面就來結(jié)合項目問題講解一下GC

1、先通過?jstat -gcutil pid interval(ms)在linux中獲取GC執(zhí)行情況

jstat -gcutil? 7698 1000

這里有11個參數(shù),參數(shù)的意思分別為:

S0:?新生代中Survivor space 0區(qū)已使用空間的百分比

S1: 新生代中Survivor space 1區(qū)已使用空間的百分比

E: 新生代已使用空間的百分比

O: 老年代已使用空間的百分比

P: 永久帶已使用空間的百分比

YGC: 從應(yīng)用程序啟動到當前,發(fā)生Yang GC 的次數(shù)

YGCT: 從應(yīng)用程序啟動到當前,Yang GC所用的時間【單位秒】

FGC: 從應(yīng)用程序啟動到當前,發(fā)生Full GC的次數(shù)

FGCT: 從應(yīng)用程序啟動到當前,F(xiàn)ull GC所用的時間

GCT: 從應(yīng)用程序啟動到當前,用于垃圾回收的總時間【單位秒】

2、下面講講垃圾回收機制GC的工作原理

JVM組成:

1.類加載器(Class?Loader):加載類文件到JVM內(nèi)存。Class loader只管加載,只要符合文件結(jié)構(gòu)就加載,至于能否運行,它不負責(zé),那是由Exectution

Engine 負責(zé)的。

2.運行時數(shù)據(jù)區(qū)(Runtime Data Area)

3.執(zhí)行引擎(Execution

Engine):也叫解釋器,負責(zé)解釋命令,交由操作系統(tǒng)執(zhí)行。

4.本地庫接口(Native

Interface):本地接口的作用是融合不同的語言為java所用


運行時數(shù)據(jù)區(qū):
?(1)堆。堆是java對象的存儲區(qū)域,任何用new字段分配的java對象實例和數(shù)組,都被分配在堆上,java堆可用-Xms和-Xmx進行內(nèi)存控制,jdk1.7以后,運行時常量池從方法區(qū)移到了堆上。

(2)方法區(qū):用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)。

(3)虛擬機棧:虛擬機棧中執(zhí)行每個方法的時候,都會創(chuàng)建一個棧楨用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。

(4)本地方法棧:與虛擬機發(fā)揮的作用相似,相比于虛擬機棧為Java方法服務(wù),本地方法棧為虛擬機使用的Native方法服務(wù),執(zhí)行每個本地方法的時候,都會創(chuàng)建一個棧幀用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。

(5)程序計數(shù)器。指示Java虛擬機下一條需要執(zhí)行的字節(jié)碼指令。


判斷垃圾算法:

●引用計數(shù)算法

??? 在 Java 中,引用和對象是有關(guān)聯(lián)的。如果要操作對象則必須用引用進行。因此,很顯然一個簡單

的辦法是通過引用計數(shù)來判斷一個對象是否可以回收。簡單說,即一個對象如果沒有任何與之關(guān) 聯(lián)的引用,即他們的引用計數(shù)都不為 0,則說明對象不太可能再被用到,那么這個對象就是可回收對象。

●可達性分析算法

?? 為了解決引用計數(shù)法的循環(huán)引用問題,Java 使用了可達性分析的方法。通過一系列的“GC roots” 對象作為起點搜索。如果在“GC

roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。要注意的是,不可達對象不等價于可回收對象,不可達對象變?yōu)榭苫厥諏ο笾辽僖?jīng)過兩次標記

過程。兩次標記后仍然是可回收對象,則將面臨回收。

回收垃圾算法:

●標記清除算法(Mark-Sweep)

●復(fù)制算法(copying)

●標記整理算法(Mark-Compact)

●分代收集算法


標記清除算法(Mark-Sweep)

最基礎(chǔ)的垃圾回收算法,分為兩個階段,標注和清除

????????????????????????????????????????????????????????????缺點:從圖中我們就可以發(fā)現(xiàn),該算法最大的問題是內(nèi)存碎片化嚴重,后續(xù)可能發(fā)生大對象不能找到可利用空間的問題。


復(fù)制算法(copying)

為了解決 Mark-Sweep 算法內(nèi)存碎片化的缺陷而被提出的算法。按內(nèi)存容量將內(nèi)存劃分為等大小

的兩塊。每次只使用其中一塊,當這一塊內(nèi)存滿后將尚存活的對象復(fù)制到另一塊上去,把已使用 的內(nèi)存清掉,如圖:


缺點:這種算法雖然實現(xiàn)簡單,內(nèi)存效率高,不易產(chǎn)生碎片,但是最大的問題是可用內(nèi)存被壓縮到了原本的一半。且存活對象增多的話,Copying 算法的效率會大大降低。

標記整理算法(Mark-Compact)

結(jié)合了以上兩個算法,為了避免缺陷而提出。標記清除階段和 Mark-Sweep 算法相同,最后將存活的對象整理到內(nèi)存的一端。如圖:

分代收集算法

1. 新生代

是用來存放新生的對象。一般占據(jù)堆的 1/3 空間。由于頻繁創(chuàng)建對象,所以新生代會頻繁觸發(fā)MinorGC 進行垃圾回收。新生代又分為 Eden 區(qū)、ServivorFrom、ServivorTo 三個區(qū)。

1.1. Eden 區(qū)

Java 新對象的出生地(如果新創(chuàng)建的對象占用內(nèi)存很大,則直接分配到老年代)。當 Eden 區(qū)內(nèi)存不夠的時候就會觸發(fā) MinorGC,對新生代區(qū)進行一次垃圾回收。

1.2. ServivorFrom上一次 GC 的幸存者,作為這一次 GC 的被掃描者。

1.3. ServivorTo保留了一次 MinorGC 過程中的幸存者。

1.4. MinorGC 的過程(復(fù)制->清空->互換)MinorGC 采用復(fù)制算法。

2.老年代.

在老年代-標記整理算法 因為對象存活率高、沒有額外空間對它進行分配

擔(dān)保, 就必須采用“標記—清除”或“標 記—整理”算法來進行回收,

不必進行內(nèi)存復(fù)制, 且直接騰出空閑內(nèi)存.

垃圾回收器

●Serial 垃圾收集器(單線程、復(fù)制算法)

●ParNew 垃圾收集器(Serial+多線程)

●Parallel

Scavenge 收集器(多線程復(fù)制算法、高效)

●Serial Old 收集器(單線程標記整理算法

●Parallel Old 收集器(多線程標記整理算法)

●CMS 收集器(多線程標記清除算法)

●G1

●ZGC?


●1.兩個收集器之間有連線,表明它們可以搭配使用。

●2.其中Serial Old作為CMS出現(xiàn)"Concurrent Mode Failure"失敗的后備預(yù)案。

●3.(紅色虛線)由于維護和兼容性測試的成本,再JDK8時將Serial+CMS、ParNew+Serial Old這兩個組合聲明為廢棄,并在JDK9完全取消了這些組合的支持,即移除。

●4.(綠色虛線)JDK14中,棄用Parallel Scavenge+SerialOld組合。刪除CMS垃圾回收器。


7種垃圾回收器的區(qū)別與特點

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容