昨天咱們用比較精簡的文字講了 Java 虛擬機結構,沒看過的能夠直接從這裏查看: 每日一問:你瞭解 Java 虛擬機結構麼?算法
今天咱們必須來看看 Java 虛擬機的垃圾回收算法是怎樣的。不過在開始以前,咱們必定得肯定哪些是活着的對象,又有哪些是能夠進行回收的。緩存
對應判斷一個對象是否能夠回收,我想引用計數必定是最容易被想到的算法了吧。給每一個對象加一個引用計數器,每當有一個地方引用它時,計數器就加 1,引用失效後減 1,當對象的計數器爲 0,則說明這個對象能夠被回收了。這個算法很是簡單,但存在一個很是大的弊端:一旦兩個對象相互引用,這個算法就沒轍了。網絡
Java 就是採用的根搜索算法進行判斷對象是否存活。這個算法的思路是:經過一系列名爲 "GC Roots" 的對象做爲起始點,從這些結點開始向下搜索,當一個對象到 "GC Roots" 沒有任何引用鏈相連的話,則證實這個對象是能夠被回收的。在 Java 中,能夠做爲 "GC Roots" 的對象包括:學習
在 JDK 1.2 以後,引用被分爲了強引用、軟引用、弱引用和虛引用四種,這四種引用強度依次逐漸減弱。code
強引用在 Android 代碼中廣泛存在,只要強引用還在,垃圾回收器就不會回收掉被引用的對象,這就是爲何咱們用內部類持有 Activity 實例會形成內存泄漏的根本緣由。對象
軟引用用來描述一些還有用,但非必需的對象,用 SoftReference
實現,**被軟引用關聯的對象,在系統將要發生 OOM 以前,會把這些對象列進回收範圍之中並進行第二次回收。**軟引用在 Android 中主要是用於作緩存,好比軟引用緩存網絡請求的圖片。生命週期
弱引用也是用來描述非必需對象的,但它的強度比軟引用更弱,用 WeakReference
實現。**被弱引用管理的對象只能生存到下一次垃圾收集發生以前。**弱引用在 Android 中主要用於處理內存泄漏。圖片
虛引用其實沒啥好說的,一個對象是否有虛引用的存在,徹底不會對生存時間構成影響,也沒法經過虛引用來取得一個對象實例。就目前爲止,我尚未在 Android 開發中使用過它。內存
學習 Java 虛擬機的垃圾回收算法以前,咱們必須來看看咱們常見的幾種垃圾回收算法的思想,並把它們的優劣進行必定的對比,這樣必定才能讓你理解更加深入。開發
標記 - 清除算法應該是最簡單基礎的收集算法了,只須要標記須要回收的對象,標記完成後統一回收便可。但其有兩個很是明顯的弊端。
複製算法主要是將可用內存劃分爲大小相等的兩塊,每次只使用其中的一塊,當這一塊內存用完,就將存活着的對象複製到另外一塊內存上去,而後把已使用過的內存空間一次性清理掉。複製回收算法能有效地避免內存碎片,可是算法須要把內存一分爲二,致使內存使用率大大下降。
複製收集算法在對象存活率較高時就須要進行較多的複製操做,效率非很低。 效率會很低。標記-整理算法就解決了這樣的問題,一樣採用的是根搜索算法進行存活對象標記,但後續是將全部存活的對象都移動到內存的一端,而後清理掉端外界的對象。
當前包括 Java 虛擬機在內的商業虛擬機都採用的是分代收集算法。這種算法其實就是根據對象的存活週期不一樣將內存劃分爲幾塊。通常把 Java 堆分爲新生代和老年代,而後根據各個年代的特色採用最適合的收集算法。
前面說了 Java 虛擬機採用的是分代回收算法,該算法會根據各個年代的特色採用最適合的收集算法,咱們就必須瞭解 Java 堆分的各個年代區域的特色。
JVM 中共分爲三個代:新生代、老年代和持久代。其中持久代主要存放的是 Java 類的類信息,與垃圾收集要收集的 Java 對象關係不大。
Java 垃圾回收包含兩種類型:Scavenge GC 和 Full GC。
System.gc()
被顯式調用;好了,這一篇文字比起前面的文字稍微多了一些,主要是知識關聯性稍微大了一些,又不適合分開講解,因此就只能這樣了。