天天學習一點JVM之:垃圾回收機制

關於JVM系列的文章,都是在讀了《深刻理解java虛擬機》一書以後的讀書筆記總結。java

每一個人入門java的時候,基本上都會聽到的關於java的一個郵電就是java的內存管理功能。使用java的時候不須要將過多的心思擺在內存管理的問題上(實際上,內存管理是開發者始終關注的話題,尤爲是移動app的開發,萬一心情很差就oom了呢)。今天簡單總結一下java的垃圾回收的知識點。android

JAVA的引用

java中引用包括下面四種:算法

  • 強引用app

    程序中廣泛存在的相似「Object object=new Object()」這種類型的引用屬於強引用。垃圾回收器永遠不會回收被強引用所引用的對象。學習

  • 軟引用cdn

    用以描述有用但卻並不是必需的對象。對於軟引用所引用的對象,在系統將要發生oom異常以前,將會對這些對象列進回收範圍之中進行第二次回收。對象

  • 弱引用blog

    用於描述非必需的對象,強度較軟引用弱。軟引用關聯的對象只能生存到下一次垃圾收集發生以前。不管當前內存是否足夠,它都會在垃圾收集器開始工做的時候被回收。內存

  • 虛引用開發

    也稱爲幽靈引用或者幻引用。虛引用的存在不會對對象的生存時間產生影響,也沒法經過虛引用取得對象的實例。爲對象設置虛引用的惟一目的就是能在這個對象唄垃圾收集器回收時收到一個系統通知。

對象存活的斷定

  • 引用計數算法

    給對象添加一個引用計數器,當有地方引用該對象時,計數器加一;引用失效時,計數器減一。任意時候,只要計數器不爲零,就表示該對象尚存在引用關係,不然表示對象不能再被使用。

  • 可達性分析算法

    以一系列能夠被稱爲gc-roots的對象爲起點並向下搜索,搜索走過的路徑爲引用鏈,當對象和gc-roots之間沒有任何的引用鏈的話,則該對象是不可用的,以下圖所示:

java中能夠被看做是gc roots的對象包括:

  • 虛擬機棧中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中常量引用的對象
  • native方法引用的對象

gc roots不可達的對象,在被回收以前至少要經歷兩次被標記的過程,才能肯定是否會被垃圾回收器回收。在對象被發現沒有引用鏈的時候,會被第一次標記而且進行一次篩選(篩選的條件是該對象有沒有必要執行finalize()方法,當對象沒有覆蓋finalize()方法或者該方法已經被虛擬機調用過的話,虛擬機都會認爲沒有必要執行finalize()方法)。若是對象沒能在finalize()方法中從新於引用鏈上的任意對象創建關聯關係,那麼對象將會在第二次標記的時候被回收。

垃圾收集算法

  • 標記-清除算法

算法分爲標記和清除兩個階段。首先標記出全部須要回收的對象,在標記完成後統一回收被標記的對象。(這個方法效率較低,並且回收以後會產生大量的不連續的內存碎片)示意圖以下所示:

  • 複製算法

將內存按容量劃分爲等大的兩塊,每次只使用其中的一塊內存,當這一塊內存將用完的時候就將還存活着的對象複製到另外一塊內存上面,而後再把已使用過的內存空間一次清理掉。示意圖以下所示:

這個算法的一種改進作法是在在回收新生代的時候,將內存分爲一塊較大的eden空間和兩塊較小的survivor空間,每次使用eden和其中的一塊survivor空間。當回收的時候,將其中還存活的對象一次性地複製到另一塊survivor空間上,最後清理掉eden和以前使用的survivor空間。

  • 標記-整理算法

標記過程於標記-清除算法同樣,可是並不直接對可回收對象進行清理,而讓全部存活的對象都往一端移動,而後清理端邊界之外的內存(針對老年代存活率比較高的現象而提出).示意圖如下所示:

  • 分代收集算法

它根據對象的存活週期的不一樣將內存劃分爲幾塊,通常是把Java堆分爲新生代和老年代。在新生代中,每次垃圾收集時都會發現有大量對象死去,只有少許存活,所以可選用複製算法來完成收集,而老年代中由於對象存活率高、沒有額外空間對它進行分配擔保,就必須使用標記—清除算法或標記—整理算法來進行回收。

簡單整理如上,若是須要更加深刻的學習的話,建議你們能夠看一下《深刻理解JVM》這本書,我的以爲寫得確實很棒。接下來,還會繼續寫一些這本書的讀書筆記。若是你們喜歡,能夠點贊收藏。有什麼問題歡迎評論一塊兒探討。你們也能夠關注我,我會在工做之餘分享本身學習android的一些東西。最後,感謝你寶貴的時間閱讀這篇文章,謝謝!

相關文章
相關標籤/搜索