JVM系列(二)--垃圾收集

如果從垃圾收集進行分析,我覺得可以從兩個方面進行:

1.如何判斷某一個對象可以進行回收

2.在哪些Runtime Data Area進行回收

3.如何進行回收

一.判斷某個對象是否可以回收

主流的商用語言,如Java及C#甚至Lisp都是採用GC Roots Tracing(根搜索算法)判斷某個對象是否可以進行回收。具體的做法是選定一些可以作爲GC Roots的對象,如:

a.JVM Stack的Stack Frame中的局部變量表中引用的對象。

b.Method Area中類的靜態屬性引用的對象。

c.Method Area中的常量引用的對象。

d.Native Method Area中引用的對象。


如果某一個對象到GC Roots沒有Reference Chain,則該對象被判定爲可以回收。


大致的回收過程如下:

1.以根搜索算法判定某個對象到GC Roots是否存在Reference Chain,進行第一次標記並判斷是否有必要執行finalize()方法。

2.如被判定有必要執行finalize()方法,則進入F-Queue隊列中,進行第二次標記,如果在finalize()執行過程中未建立到GC Roots的Reference Chain,則該對象註定要被回收,反之則被移除即將會後的集合。


二.在哪些區域進行回收

分析這個問題需要從分配的角度去理解:

前提,Java Heap 可以分爲新生代與老年代

1.大多數情況下,對象在新生代Eden區中分配。

2.大對象直接進入老年代。

3.長期存活的對象進入老年代。

根據以上分配策略,可以知道,回收主要發生在Java Heap中。


是否要對Method Area進行回收?

首先我們知道,HotSpot的Method Area存在垃圾回收。

根據以往的數據分析結果,Method Area發生的垃圾回收效率太低,主要因爲以下原因:

Method Area中垃圾回收主要針對廢棄的常量和無用的類,回收廢棄的常量較爲容易,但是回收無用的類卻較爲麻煩,因爲一個類是否需要回收的判定條件太苛刻:

1.該類所有的實例都已經被回收,即Java Heap中不存在該類的任何實例

2.加載該類的ClassLoader已經被回收

3.該類對應的java.lang.Class對象沒有在任何地方被引用,無法在熱河地方通過反射訪問該類的方法

當然,可以通過一下幾個參數進行控制:

-Xnoclassgc 不回收類


三.如何進行回收

先來看幾種垃圾回收算法的原理及優缺點:

1.Mark-Sweep(標記清除)算法

先標記,後清除。

缺點:容易產生大量的不連續內存(內存碎片),這樣在分配大對象時較爲麻煩。


2.Copying(複製算法)

複製算法的思想:

將內存非爲兩塊,每次只使用一塊,當這一塊用完了,就將這塊內存中存活的對象複製到另外一塊內存上,然後將第一塊內存中的對象進行一次性回收。

優點:高效

缺點:將內存一份爲二,代價較高。

現在的商業虛擬機都使用這種算法對新生代進行回收,如HotSpot對新生代進行回收的方式:

將新生代分爲Eden空間、From Survivor空間、To Survivor空間,默認比例爲8:1:1

每次回收時將Eden空間與其中一塊Survivor空間中存活的對象複製到另外一塊Survivor空間上,然後進行清除,這其中還涉及到分配擔保的概念

3.Mark-Compact(標記整理)算法

針對老年代的回收算法

每次回收時進行整理,將未被標記的對象(存活對象)移動到一端,然後清理掉邊界以外的內存。


4.Generational Collection(分代收集)

分代垃圾回收的思想是針對不同區域的特點,在不同區域應用不同的回收算法。

新生代:Mark-Copying-Sweep

老年代: Mark-Compact-Sweep



Minor GC與Full GC

Minor GC即新生代GC,主要針對Java Heap的新生代,Minor GC較爲頻繁快速。

Full GC即老年代GC,主要針對Java Heap的老年代,Full GC較Minor GC慢10倍左右。


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