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