JVM的垃圾回收算法一起來看看
垃圾回收算法
概念
垃圾回收(Garbage Collection,GC)。程序的運(yùn)行需要資源,無效的對象如果不及時(shí)清理就會(huì)一直占用資源,所以對內(nèi)存資源管理就變得十分重要。而Java為了讓我們更多的關(guān)注代碼本身,而不用過多的考慮內(nèi)存的釋放問題,就有了我們十分熟悉的GC。然而當(dāng)垃圾回收成為系統(tǒng)達(dá)到更高并發(fā)量的瓶頸時(shí),我們就需要對這些自動(dòng)化的技術(shù)進(jìn)行一系列的監(jiān)控和調(diào)節(jié)。
GC主要需要完成三件事情 :
哪些內(nèi)存需要回收? 什么時(shí)候回收? 如何回收?
哪些垃圾需要回收呢?這個(gè)時(shí)候我們?nèi)绾闻袛嗄男ο?ldquo;活著”,哪些對象“死去”?于是就有了標(biāo)記算法。
1.標(biāo)記算法
垃圾收集器中標(biāo)記算法有兩種,引用計(jì)數(shù)法和根可達(dá)算法
1.1 引用計(jì)數(shù)法(Reference Counting)
引用計(jì)數(shù)算法很簡單,它實(shí)際上是通過在對象頭中分配一個(gè)空間來保存該對象被引用的次數(shù)。如果該對象被其它對象引用,則它的引用計(jì)數(shù)加1,如果刪除對該對象的引用,那么它的引用計(jì)數(shù)就減1,當(dāng)該對象的引用計(jì)數(shù)為0時(shí),那么該對象就會(huì)被回收。
如:
A objA = new A(); B objB = new B(); objA.ref = objB;
如圖:
對象 A 的實(shí)例在Java堆中就是一塊內(nèi)存而已,而objA 做為一個(gè)局部變量引用了它,所以它的引用計(jì)數(shù)就是1,對象B的實(shí)例在堆中也是一塊內(nèi)存,objB這個(gè)局部變量引用了它,然后objA又引用了它一次,所以它的引用計(jì)數(shù)就是2。
客觀來說,引用計(jì)數(shù)算法 效率高,實(shí)現(xiàn)簡單,然而,Java虛擬機(jī)沒有選取引用計(jì)數(shù)算法來管理內(nèi)存,主要是因?yàn)闊o法解決 循環(huán)引用的問題。
如:
objA.ref= objB; objB.ref= objA
如圖:
實(shí)際上這兩個(gè)對象已經(jīng)不可能再被訪問,但是它們因?yàn)榛ハ嘁弥鴮Ψ剑瑢?dǎo)致它們的引用計(jì)數(shù)都不為0,于是這兩個(gè)對象都無法被GC回收。
1.2 可達(dá)性分析算法(Reachable Analysis)
在Java中是通過可達(dá)性分析算法來判斷對象是否存活的。選定一系列稱為"GC ROOTS"的對象作為起始點(diǎn),從這些對象向下搜索,搜索所走過的道路稱為引用鏈(Reference Chain).當(dāng)一個(gè)對象到GC ROOTS沒有任何引用鏈時(shí),則不可達(dá),這些對象會(huì)被判定可以回收。
如圖:
在Java中,能作為GC Roots的對象包含以下幾種
虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象 方法區(qū)中類靜態(tài)屬性引用的對象 方法區(qū)中常量引用的對象 本地方法棧JNI(即一般說的Native方法)當(dāng)中引用的對象
2.回收算法
當(dāng)成功區(qū)分出哪些是存活對象哪些是死亡對象之后,GC接下來的任務(wù)就是執(zhí)行垃圾回收,釋放掉無用對象所占用的內(nèi)存空間,以便有足夠的可用內(nèi)存空間為新對象分配內(nèi)存。常用的垃圾回收算法有 標(biāo)記清除算法、復(fù)制算法、標(biāo)記壓縮算法。
2.1 標(biāo)記清除算法 (Mark Sweep)
標(biāo)記清除算法是最基礎(chǔ)的垃圾回收算法,同它的名字一樣,該算法有兩個(gè)過程,首先標(biāo)記哪些是可回收的對象,然后進(jìn)行內(nèi)存回收
標(biāo)記: Collector從引用根結(jié)點(diǎn)開始遍歷,標(biāo)記所有被引用的對象。一般是在對象的Header中記錄為可達(dá)對象。
清除: Collector對堆內(nèi)存從頭到尾進(jìn)行線性的遍歷,如果發(fā)現(xiàn)某個(gè)對象在其Header中沒有標(biāo)記為可達(dá)對象,則將其回收。從網(wǎng)上找張圖給大家解釋一下,
如圖:
缺點(diǎn):
1.效率不高,標(biāo)記過程和清除過程效率都一般
2.會(huì)產(chǎn)生很多空間碎片,可能會(huì)導(dǎo)致以后為大對象分配空間時(shí)因?yàn)檎也坏娇捎玫倪B續(xù)內(nèi)存空間不得不再次進(jìn)行GC。
2.2 復(fù)制算法(Copying)
GC復(fù)制算法(Copying GC)是由Marvin L. Minsky在1963年研究出來的算法。原理是把內(nèi)存分為兩個(gè)空間一個(gè)是From空間,一個(gè)是To空間,對象一開始只在From空間分配,To空間是空閑的。GC時(shí)把存活的對象從From空間復(fù)制粘貼到To空間,之后把To空間變成新的From空間,原來的From空間變成To空間。回收前后對比下圖所示:
如圖:
優(yōu)缺點(diǎn):
1.復(fù)制算法實(shí)現(xiàn)簡單運(yùn)行高效,不會(huì)產(chǎn)生內(nèi)存碎片
2.但是將內(nèi)存縮小為原本的一半,代價(jià)略高。
現(xiàn)在虛擬機(jī)基本都采用這種垃圾回收算法回收新生代
2.3 標(biāo)記壓縮算法(Mark-Compact)
標(biāo)記壓縮算法(Mark-Compact),標(biāo)記過程和標(biāo)記清除算法的標(biāo)記過程一樣,但是清理過程不同,會(huì)將存活對象移動(dòng)到一端,然后清理掉端邊界之外的內(nèi)存,
如圖:
優(yōu)缺點(diǎn):
標(biāo)記整理算法效率低,但不用浪費(fèi)內(nèi)存,也不會(huì)造成內(nèi)存碎片。
2.4 分代回收算法
因?yàn)樾律鷮ο蟠罅克廊?,少量存活,一般采用?fù)制算法。老年代存活率高,回收的少,一般采用MC/MS(標(biāo)記清除/標(biāo)記壓縮)
如圖是我用arthas的dashboard命令輸出的本地的Memory信息。jdk1.8默認(rèn)的垃圾回收器是ps+po(這個(gè)之后講)??梢钥吹叫律笮。ㄒ恋閰^(qū)和s區(qū)),老年代大小。
2.4.1 新生代(Eden區(qū)/伊甸區(qū))
年輕代的對象處于一種“朝生夕死”的狀態(tài),在年輕代的GC叫做YGC(Minor GC)。Eden區(qū)對象活過第一次垃圾回收之后會(huì)進(jìn)入survivor區(qū)(S0S1/S1S2)。在S1,S2之間經(jīng)過多次垃圾回收進(jìn)入老年代。
-XX:MaxTenuringThreshold 可以配置多少次從年輕代進(jìn)入老年代
在多線程那我們整過這張圖,再看一下,分代年齡只有4bit,意味著對象的最大年齡只有15-----可以通過上面的參數(shù)設(shè)置大小,最大15,之后要是沒有被gc就會(huì)進(jìn)入老年代。
2.4.2 老年代(tenured/old)
進(jìn)入老年代的對象大多數(shù)活過了年輕代的多次gc,因此不會(huì)頻繁死亡,老年代的GC叫做(Major GC)FULL GC。FGC的效率比YGC低的多,在老年代無法繼續(xù)分配空間的時(shí)候觸發(fā),觸發(fā)是新生代老年代一起進(jìn)行回收。
2.4.3 新生代何時(shí)進(jìn)入老年代
1. 超過 XX:MaxTenuringThreshold 指定次數(shù) 2. 動(dòng)態(tài)年齡,S0->S1超過50%,把年齡最大的放到Old 3. 分配擔(dān)保:YGC期間,survivor區(qū)空間不夠了,空間擔(dān)保直接進(jìn)入老年代
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
解讀java?try?catch?異常后還會(huì)繼續(xù)執(zhí)行嗎
這篇文章主要介紹了解讀java?try?catch?異常后還會(huì)不會(huì)繼續(xù)執(zhí)行問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Mybatis邏輯分頁與物理分頁P(yáng)ageHelper使用解析
這篇文章主要為大家介紹了Mybatis邏輯分頁與物理分頁P(yáng)ageHelper使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12idea配置maven環(huán)境時(shí)maven下載速度慢的解決方法
我們在idea配置maven環(huán)境的時(shí)候會(huì)發(fā)現(xiàn)maven更新慢的現(xiàn)象,解決辦法就是下載國內(nèi)的鏡像包,完美解決下載速度慢的問題,文中有詳細(xì)的具體操作方法,并通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02數(shù)據(jù)結(jié)構(gòu)與算法之手撕排序算法
排序算法看似簡單,其實(shí)不同的算法中蘊(yùn)涵著經(jīng)典的算法策略。通過熟練掌握排序算法,就可以掌握基本的算法設(shè)計(jì)思想,本文主要介紹了Java中的排序算法,需要的朋友歡迎閱讀2023-04-04Java中的非對稱加密算法原理與實(shí)現(xiàn)方式
在當(dāng)今的信息時(shí)代,數(shù)據(jù)安全已經(jīng)成為了一個(gè)至關(guān)重要的問題,加密技術(shù)作為保障信息安全的重要手段,受到了廣泛的應(yīng)用和關(guān)注,本篇文章將詳細(xì)介紹Java中的非對稱加密算法原理及其實(shí)現(xiàn)方式,需要的朋友可以參考下2023-12-12使用maven實(shí)現(xiàn)有關(guān)Jsoup簡單爬蟲的步驟
這篇文章主要介紹了使用maven實(shí)現(xiàn)有關(guān)Jsoup簡單爬蟲的步驟,文中附含詳細(xì)示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09