垃圾回收機制淺聊

對於任何一門語言而言,在運行過程中都會創建許多對象,繼而需要爲這些對象分配內存地址,當這些對象不需要使用的時候,需要釋放其佔用的內存地址,以供新的對象使用。關於對象內存釋放的這一機制就叫做垃圾回收機制(GC)。
Java中垃圾回收是自動化的,但其可控性差,內存容易溢出。內存溢出是因爲JVM內存分配的對象過多,這些對象所需內存超出了JVM內存大小。雖然Java中是自動的。但是程序員仍可調用System.gc( )來進行手動回收,調用此方法會嘗試釋放被丟棄的對象佔用的內存,但結果無法保證,因此附帶一個免責聲明。下面我們將從如何確定需要被回收的對象、什麼時候回收、怎樣進行回收這三個方面進行分析。

確定回收對象:

確定回收對象有兩個算法:引用計數法與可達性分析法。【引用計數法】系統會爲對象添加一個計數器,當有新的引用時加1,引用失效時減1。但是此方法無法解決兩個對象循環引用的問題。【可達性分析法】通過對象的引用鏈來判斷該對象是否需要被回收,通過一系列的GC Roots的對象作爲起始點,從這些根節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的,就需要回收此對象。
這裏寫圖片描述

回收時間:

CPU空閒時進行回收、堆內存滿了後進行回收、調用System.gc()回收。

回收方法:

【標記-清除算法】首先標記需要回收的對象,然後進行回收;缺點:回收速度慢,回收之後產後生大量不連續的內存碎片,後期運行過程中需要分配較大對象時無法找到足夠的連續內存而造成內存空間浪費。
這裏寫圖片描述

【複製算法】將內存空間等分爲兩份,每次只使用其中一份,當滿了之後將還有效的對象複製到另一份內存中,,然後把原來的空間進行清除,不會產生內存碎片,但是可用內存空間減半。
這裏寫圖片描述

【標記-整理算法】不僅對需要回收的對象進行整理,還對有效對象進行整理,不會產生內存碎片。
這裏寫圖片描述

【分代收集算法】是一種比較智能的算法,也是現在JVM使用最多的一種算法,其實不是一個新的算法,而是在具體的場景自動選擇以上三種算法進行垃圾對象回收。
新生代:目的是回收那些生命週期短的對象,主要存放新產生的對象。新生代按照8:1:1分爲eden區、survivor0、survivor1,大部分對象在eden區中生成,當eden滿時,將存活的對象複製到survivor0,然後清空eden,當eden、survivor0都滿了時,將這兩個區中存活的對象複製到survivor1,然後清空eden、survivor0,當着三個區都滿了時則把存貨對象複製到老年代,如果老年代也滿了則觸發FullGC。新生代的全回收叫MinorGC,MinorGC發生頻率比較高,不一定等到新生代滿了時才進行。
老年代:存放對象生命週期較長,且內存大概是新生代的兩倍,老年代存活對象生命週期長,因此MajorGC發生頻率較低。
永久代:主要存放靜態文件,如Java類,方法等。永久帶對垃圾回收基本沒有影響,當應用動態生成或者調用一些類的時候,例如反射、動態代理CGLib等bytecode框架時需要永久帶來保存新生成的類。

總結:【1】在新生代中,每次垃圾收集時都有大批對象死去,只有少量存活,那就選用複製算法。只需要付出少量存活對象的複製成本就可以完成收集。【2】老年代中因爲對象存活率高、沒有額外空間對他進行分配擔保,就必須用標記-清除或者標記-整理。
由於永久代經常會內存不夠用或者發生內存泄露,JDK1.8開始廢棄了永久代,取而代之的是元空間(直接存在內存中可自定義大小),主要存放類的元數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章