淺談垃圾回收算法

首先給你們講一個梗,爲何Java程序員愈來愈多,而C++程序員愈來愈少呢?—— 那還不是由於不用管理內存啊程序員

在C++中,本身new的對象,在不用的時候須要手動釋放。而在Java裏,你能夠釋放你的雙手,將這項工做交給JVM本身管理。在JVM裏面,這種機制叫作垃圾回收(Garbage Collection)機制。
算法

ps:本文不涉及垃圾收集器,主要是講垃圾回收的思路。cdn

Java內存管理

Java的變量一共存儲在三個地方、方法區、堆、棧對象

方法區

主要存放常量,靜態常量、常量池,在程序編譯的時候,這塊內存就已經被分配出來了,伴隨程序的一輩子。blog

是JVM管理的內存最大的一塊,存放全部的實例對象,也是垃圾收集器管理的主要區域。也稱爲「GC堆」生命週期

當方法被執行的時候,方法內部的局部變量就會被存儲在棧裏,當方法執行完畢的時候,剛剛存儲的局部變量會被自動釋放。ip

回收流程

  1. 首先會判斷對象是否存活
  2. 利用回收算法對對象進行回收

如何判斷對象是否存活?

前面說到垃圾收集器管理的是堆,在回收以前,一般須要判斷這個對象是不是存活的。內存

引用計數法

遍歷對象,當這個對象被其餘對象引用的時候計數器就加1,當引用失效的時候,計數器減1。當對象的計數器爲0時,則表示該對象沒有被引用。這種方法效率很高,可是沒法解決互相引用的問題。所以主流JVM都未採用這種方法。虛擬機

可達性分析

這一算法的思想是從GC Roots做爲起始點,從這些節點往下搜索,搜索的路徑叫作引用鏈,當一個對象沒有任何引用鏈能夠到GC ROOT的時候,則證實該對象是不可用的。通常想要宣告一個對象死亡,至少要經歷兩次標記,即標記-篩選-標記。 it

image

垃圾回收算法

標記-清除

過程
  1. 標記出全部須要回收的對象
  2. 清除全部被標記的對象

不足:

  1. 清除和標記兩個效率都不高。
  2. 會產生大量的內存碎片,會致使在分配較大對象的時候,若是找不到足夠的空間會再次清除。

image

複製算法

過程:

將可用內存分爲兩塊,每次只使用其中的一塊。一塊內存使用完的時候,將存活下來的對象複製到另外一塊中,再清除這一塊內存。這樣就沒什麼內存碎片可言了。

優勢:

效率高,解決了內存碎片的問題。

缺點:只能使用一半的空間。

image
不過現代虛擬機幾乎都不是1:1分配空間,由於大部分都對象的生命週期都不長。例如HotSpot虛擬機,默認的Eden和Survivor的大小比例是8:1。

標記 — 整理算法

複製-收集算法,在對象存活率高的狀況下,要進行屢次複製,效率比較低。因此說爲此提出了「標記-整理」算法。

過程:

標記過程同上,而後讓全部存活的對象移動到另外一端,而後清理掉邊界外的內存。

image

分代收集算法

分代收集算法比較常見,通常把堆分爲新生代和老年代,這樣能夠根據各個年代的特色採用適當的算法。

  • 新生代:新生代會有大批對象死去,少許對象存活。適合複製算法。
  • 老年代:老年代中對象存活率較高,沒有額外 空間來分配擔保。因此說適合採用標記-清除 或 標記-整理算法。
    ps:空間分配擔保是用來檢測老年代最大可用的連續空間是否大於新生代全部活着的對象的總空間。

引用類型

在JDK1.2以後,Java對引用的概念進行了擴充,將引用分爲強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)四種,這四種引用強度依次逐漸減弱。

強引用(Strong reference)

就是指在程序代碼之中廣泛存在的,例如new出來的對象,只要強引用還在,該對象就不會被回收。

軟引用(Soft Reference)

用來描述一些還有用但並不是必須的對象。在內存即將溢出以前,垃圾收集器會將這些對象進行回收。

弱引用(Weak Reference)

用戶描述非必須對象的。不管當前內存是否足夠,隨時都有可能被回收。

虛引用(Phantom Reference)

虛引用不會影響該對象都生命週期,只會在該對象被回收的適合得到一個系統通知。

相關文章
相關標籤/搜索