淺談Java垃圾回收機(jī)制
一.什么是垃圾
java中,什么樣的對象是垃圾?有人說:沒有被引用的對象就是垃圾對象.我一開始對此也是深信不疑的,但是當(dāng)年我這么回答面試官的時(shí)候,得到的是一個(gè)大大的白眼.
判斷一個(gè)對象是否是垃圾,有兩種算法,一種是引用計(jì)數(shù)法,但是,這種方法解決不了循環(huán)引用的問題.
/**循環(huán)問題*/ public class Demo{ public Demo instance; public static void main(String[] args) { Demo a=new Demo(); Demo b=new Demo(); a.instance=b; b.instance=a; a=null; b=null; } }
另外一種方法,可以解決這種循環(huán)引用問題,那就是可達(dá)算法.關(guān)于可達(dá)算法,就我目前所知道的,有兩種解釋:
大眾說法:
通過一系列的稱謂“GC Roots”的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所有走過的路徑為引用鏈,當(dāng)一個(gè)對象到GC Roots沒有任何引用鏈項(xiàng)鏈時(shí),則證明此對象時(shí)不可用的.
某位前輩的理解:
選取一個(gè)對象作為GC Roots,調(diào)用其它對象去指向這個(gè)GC Roots,如果這些對象最終到達(dá)GC Roots,那表明所選取的對象不是垃圾.反之,如果對象到不了GC Roots,那么所選取的對象就是垃圾對象,就可以進(jìn)行垃圾回收了.(這是一種說法);
對象指向GC Roots所形成的鏈條叫GC鏈.
至于這兩種方法誰對誰錯(cuò),這就要看個(gè)人的水平了.
不管怎么樣,垃圾反正是產(chǎn)生了,那么接下來就是該怎么回收垃圾了.
二.怎么回收垃圾
2.1 靜態(tài)對象什么時(shí)候變成垃圾被回收
在說垃圾回收前,先說一個(gè)題外話,我上面所說的垃圾對象,其實(shí)是指一般的對象,因?yàn)殪o態(tài)對象有些不同.
我經(jīng)常聽人說:靜態(tài)方法隨著類的加載而加載,隨著類的消失而消失.但是,現(xiàn)在在我看來,這種說法是有問題的.
因?yàn)?靜態(tài)對象要成為垃圾被回收,要滿足三個(gè)條件:
1. 這個(gè)類的對象變成了垃圾
2. 加載這個(gè)類的類加載器變成了垃圾
3. 關(guān)于這個(gè)對象的class對象也變成了垃圾
只有滿足這三個(gè)條件,靜態(tài)對象才會(huì)變成垃圾被回收,要不然靜態(tài)對象會(huì)一直存在于永久帶中.
2.2 新生代和年老代
既然要說垃圾回收,那么我們就先來看看跟垃圾回收密切相關(guān)的堆內(nèi)存(新生代和年老代)
如圖所示:
堆內(nèi)存按1:2被劃分成了年輕代(新生代)和年老代.新生代又被按照8:1:1的比例分為一個(gè)eden區(qū)和兩個(gè)survivor(survivor0,survivor1)區(qū)
關(guān)于分區(qū),我只講到這里,有興趣的可以自己研究.
三、垃圾回收算法
3.1 標(biāo)記清除算法
如圖所示:標(biāo)記清除算法分成兩步,第一步,標(biāo)記要回收的垃圾對象,第二步就是清除被標(biāo)記的垃圾對象.
同樣,如圖所示,標(biāo)記清除算法會(huì)產(chǎn)生大量的內(nèi)存碎片,而且效率低.所以,為了解決這個(gè)問題,出現(xiàn)了復(fù)制清除算法.
3.2 復(fù)制清除算法(專門用于處理年輕代垃圾的)
如圖所示,所謂復(fù)制清除算法,就是在要進(jìn)行垃圾回收的時(shí)候,先將活著的對象整齊的復(fù)制到一塊空閑區(qū)域,然后再將原來的區(qū)域的垃圾全部清除.
復(fù)制清除算法的優(yōu)點(diǎn):效率高于標(biāo)記清除算法,活著的對象是整齊排列的,沒有內(nèi)存碎片.
但是這個(gè)方法的缺點(diǎn)也很明顯,那就是浪費(fèi)空間.,畢竟如果按照1:1比例來劃分空間的話,那么將會(huì)有50%的空間被浪費(fèi).不過,在jvm中,年輕代空間并不是按照1:1來劃分的,而是按照8:1:1的比例分為一個(gè)eden區(qū)和兩個(gè)survivor(survivor0,survivor1)區(qū)。一個(gè)Eden區(qū),兩個(gè) Survivor區(qū)(一般而言)。大部分對象在Eden區(qū)中生成?;厥諘r(shí)先將eden區(qū)存活對象復(fù)制到一個(gè)survivor0區(qū),然后清空eden區(qū),當(dāng)這個(gè)survivor0區(qū)也存放滿了時(shí),則將eden區(qū)和survivor0區(qū)存活對象復(fù)制到另一個(gè)survivor1區(qū),然后清空eden和這個(gè)survivor0區(qū),此時(shí)survivor0區(qū)是空的,然后將survivor0區(qū)和survivor1區(qū)交換,即保持survivor1區(qū)為空,這樣的過程也被叫做Minor GC,每進(jìn)行Minor GC一次,存活著的對象的年齡就會(huì)加1,當(dāng)存活著的對象的年齡到達(dá)15歲時(shí),就會(huì)被送進(jìn)年老代.
當(dāng)然,當(dāng)整個(gè)當(dāng)survivor1區(qū)不足以存放 eden和survivor0的存活對象時(shí),也會(huì)將存活對象直接存放到年老代。若是年老代也滿了就會(huì)觸發(fā)一次Full GC,也就是新生代、老年代都進(jìn)行回收
3.3 標(biāo)記清理算法(年老代)
將活著的對象一個(gè)接一個(gè)的按順序排好,然后再清除變成垃圾的對象.這種方法不會(huì)造成碎片,也不會(huì)造成內(nèi)存的浪費(fèi).但是效率不高.所以,這種方法不適合在年輕代使用,而是在對象生命力很頑強(qiáng)的年老代使用
3.4 分類算法
所謂分類算法,就是根據(jù)內(nèi)存的不同,采用不同的垃圾回收方式(上面的1,2,3)進(jìn)行垃圾回收.
暫時(shí)就先說到這里,因?yàn)樵僬f下去,還會(huì)有什么GC停頓以及垃圾收集器等.如果大家想要了解更多的垃圾回收的知識,可以看類似<<深入理解Java虛擬機(jī):JVM高級特性與最佳實(shí)踐>>等書籍.畢竟這些書是我的一位前輩推薦給我的.
到此這篇關(guān)于淺談Java垃圾回收機(jī)制的文章就介紹到這了,更多相關(guān)Java垃圾回收內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java簡單實(shí)現(xiàn)桌球滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了java簡單實(shí)現(xiàn)桌球滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10MyBatis傳入List集合查詢數(shù)據(jù)問題
這篇文章主要介紹了MyBatis傳入List集合查詢數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Spring加載properties文件的兩種方式實(shí)例詳解
這篇文章主要介紹了Spring加載properties文件的兩種方式,需要的朋友可以參考下2018-02-02SpringCloud @RefreshScope刷新機(jī)制深入探究
RefeshScope這個(gè)注解想必大家都用過,在微服務(wù)配置中心的場景下經(jīng)常出現(xiàn),他可以用來刷新Bean中的屬性配置,那大家對他的實(shí)現(xiàn)原理了解嗎?它為什么可以做到動(dòng)態(tài)刷新呢2023-03-03Java中HashMap和Hashtable及HashSet的區(qū)別
以下是對Java中HashMap和Hashtable及HashSet的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-09-09Spring+SpringMVC+MyBatis整合詳細(xì)教程(SSM)
Spring是一個(gè)開源框架,Spring是于2003 年興起的一個(gè)輕量級的Java 開發(fā)框架。這篇文章主要介紹了Spring+SpringMVC+MyBatis整合詳細(xì)教程(SSM),需要的朋友可以參考下2017-10-10