詳解GC機制,gc機制,Android垃圾回收機制的底層描述

   GC概念:

 什麼是GC機制?

字面是說是“垃圾收集”,更精確點就是“內存回收”,在一個對象不再被程序引用時,它所佔用的堆空間就可以回收,以便分配給新對象使用。

先認識三個英語:

(Minor GC) vs (Major GC) vs (Full GC)

  • Minor GC從年輕代空間(包括 Eden 和 Survivor 區域)回收內存被稱爲 Minor GC。這一定義既清晰又易於理解。
  • Major GC 是清理老年代。
  • Full GC 是清理整個堆空間—包括年輕代和老年代。


 

在瞭解回收機制之前要先了解的知識有哪些?

在瞭解回收機制之前,必須要了解內存,所以,本文先從內存簡單的描述以下,,幫助瞭解回收機制的整個過程


步驟:

(1,JVM是怎麼分配內存的,,2,識別哪些內存是垃圾需要回收,,3,最後纔是用什麼方式回收。)

 棧的內存管理是順序分配的,而且定長,不存在內存回收問題;而堆 則是爲java對象的實例隨機分配內存,不定長度,所以存在內存分配和回收的問題;

   一,內存分配:

Java虛擬機是先一次性分配一塊較大的空間,然後每次new時都在該空間上進行分配和釋放,減少了系統調用的次數,節省了一定的開銷,這有點類似於
內存池的概念;二是有了這塊空間過後,如何進行分配和回收就跟GC機制有關了。

java一般內存申請有兩種:靜態內存和動態內存


很容易理解,編譯時就能夠確定的內存就是靜態內存,即內存是固定的,系統一次性分配,比如int類型變量;動態內存分配就是在程序執行時才知道要分配的存儲空間大小,比如java對象的內存空間。

二,垃圾的回收方法及思路:

垃圾收集器一般必須完成兩件事:檢測出垃圾;回收垃圾。怎麼檢測出垃圾?一般有以下幾種方法:



(檢測垃圾的算法)
引用計數法:

給一個對象添加引用計數器,每當有個地方引用它,計數器就加1;引用失效就減1。
好了,問題來了,如果我有兩個對象A和B,互相引用,除此之外,沒有其他任何對象引用它們,實際上這兩個對象已經無法訪問,即是我們說的垃圾對象。但是互相引用,計數不爲0,導致無法回收,所以還有另一種方法:


可達性分析算法:

以根集對象爲起始點進行搜索,如果有對象不可達的話,即是垃圾對象。這裏的根集一般包括java棧中引用的對象、方法區常良池中引用的對象
本地方法中引用的對象等。
總之,JVM在做垃圾回收的時候,會檢查堆中的所有對象是否會被這些根集對象引用,不能夠被引用的對象就會被垃圾收集器回收。一般回收算法也有如下幾種:



(處理垃圾的算法)


1.標記-清除(Mark-sweep)


算法和名字一樣,分爲兩個階段:標記和清除。標記所有需要回收的對象,然後統一回收。這是最基礎的算法,後續的收集算法都是基於這個算法擴展的。
不足:效率低;標記清除之後會產生大量碎片。


2.複製(Copying)


此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另外一個區域中。此算法每次只處理正在使用中的對象,因此複製成本比較小,同時複製過去以後還能進行相應的內存整理,不會出現“碎片”問題。當然,此算法的缺點也是很明顯的,就是需要兩倍內存空間。 


3.標記-整理(Mark-Compact)
此算法結合了“標記-清除”和“複製”兩個算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把清除未標記對象並且把存活對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-清除”的碎片問題,同時也避免了“複製”算法的空間問題。 


4.分代收集算法(當今最常用的方法)
這是當前商業虛擬機常用的垃圾收集算法。分代的垃圾回收策略,是基於這樣一個事實:不同的對象的生命週期是不一樣的。因此,不同生命週期的對象可以採取不同的收集方式,以便提高回收效率。
爲什麼要運用分代垃圾回收策略?在java程序運行的過程中,會產生大量的對象,因每個對象所能承擔的職責不同所具有的功能不同所以也有着不一樣的生命週期,有的對象生命週期較長,比如Http請求中的Session對象,線程,Socket連接等;有的對象生命週期較短,比如String對象,由於其不變類的特性,有的在使用一次後即可回收。試想,在不進行對象存活時間區分的情況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,而且對於存活時間較長的對象進行的掃描工作等都是徒勞。因此就需要引入分治的思想,所謂分治的思想就是因地制宜,將對象進行代的劃分,把不同生命週期的對象放在不同的代上使用不同的垃圾回收方式。
如何劃分?


將對象按其生命週期的不同劃分成:


年輕代(Young Generation)、
年老代(Old Generation)、
持久代(Permanent Generation)。

其中持久代主要存放的是類信息,所以與java對象的回收關係不大,與回收息息相關的是年輕代和年老代。這裏有個比喻很形象
“假設你是一個普通的 Java 對象,你出生在 Eden 區,在 Eden 區有許多和你差不多的小兄弟、小姐妹,可以把 Eden 區當成幼兒園,在這個幼兒園裏大家玩了很長時間。Eden 區不能無休止地放你們在裏面,所以當年紀稍大,你就要被送到學校去上學,這裏假設從小學到高中都稱爲 Survivor 區。開始的時候你在 Survivor 區裏面劃分出來的的“From”區,讀到高年級了,就進了 Survivor 區的“To”區,中間由於學習成績不穩定,還經常來回折騰。直到你 18 歲的時候,高中畢業了,該去社會上闖闖了。於是你就去了年老代,年老代裏面人也很多。在年老代裏,你生活了 20 年 (每次 GC 加一歲),最後壽終正寢,被 GC 回收。有一點沒有提,你在年老代遇到了一個同學,他的名字叫愛德華 (慕光之城裏的帥哥吸血鬼),他以及他的家族永遠不會死,那麼他們就生活在永生代。”





年輕代:


是所有新對象產生的地方。

年輕代被分爲3個部分——Enden區和兩個Survivor區(From和to)

當Eden區被對象填滿時,就會執行Minor GC。並把所有存活下來的對象轉移到其中一個survivor區(假設爲from區)。Minor GC同樣會檢查存活下來的對象,並把它們轉移到另一個survivor區(假設爲to區)。這樣在一段時間內,總會有一個空的survivor區。經過多次GC週期後,仍然存活下來的對象會被轉移到年老代內存空間。通常這是在年輕代有資格提升到年老代前通過設定年齡閾值來完成的。

需要注意,Survivor的兩個區是對稱的,沒先後關係,from和to是相對的。



年老代:


在年輕代中經歷了N次回收後仍然沒有被清除的對象,就會被放到年老代中,可以說他們都是久經沙場而不亡的一代,都是生命週期較長的對象。對於年老代和永久代,就不能再採用像年輕代中那樣搬移騰挪的回收算法,因爲那些對於這些回收戰場上的老兵來說是小兒科。這時候MajsorGC會清理些老年代垃圾,通常會在老年代內存被佔滿時將會觸發Full GC,回收整個堆內存。
持久代:用於存放靜態文件,比如java類、方法等。持久代對垃圾回收沒有顯著的影響。 
  

垃圾收集器
垃圾收集算法是內存回收的方法論,而實現這些方法論的則是垃圾收集器。這裏就不詳細描述了。



GC中對象的六種可觸及狀態
   1.強可觸及:對象可以從根結點不通過任何引用對象搜索到
   2.軟可觸及:對象不是強可觸及的,但是可以從根結點開始通過一個或多個(未被清除的)軟引用對象觸及
   3.弱可觸及:對象既不是強可觸及也不是軟可觸及的,但是從根結點開始

   4.可復活的:對象既不是強可觸及、軟可觸及,也不是弱可觸及,但是仍然可能通過執行某些終結方法復活到這幾種狀態之一
   5.影子可觸及:不上以上任何可觸及狀態,也不能通過終結方法復活,並且它可以從根結點開始通過一個或多個影子引用對象觸及(影子引用不會被垃圾收集器清除,由程序明確地清除)
   6不可觸及:就是已經準備回收的狀態

發佈了39 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章