天天看點

[jjzhu學java]之深入了解JVM之垃圾收集器與記憶體配置設定政策深入了解JVM之垃圾收集器與記憶體配置設定政策

<a href="#%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3jvm%e4%b9%8b%e5%9e%83%e5%9c%be%e6%94%b6%e9%9b%86%e5%99%a8%e4%b8%8e%e5%86%85%e5%ad%98%e5%88%86%e9%85%8d%e7%ad%96%e7%95%a5">深入了解jvm之垃圾收集器與記憶體配置設定政策</a>

<a href="#%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%af%b9%e8%b1%a1%e5%b7%b2%e7%bb%8f%e6%b6%88%e4%ba%a1">如何判斷對象已經消亡</a>

<a href="#%e5%bc%95%e7%94%a8%e8%ae%a1%e6%95%b0%e7%ae%97%e6%b3%95">引用計數算法</a>

<a href="#%e6%a0%b9%e6%90%9c%e7%b4%a2%e7%ae%97%e6%b3%95">根搜尋算法</a>

<a href="#%e5%bc%95%e7%94%a8">引用</a>

java中對象的建立需要的記憶體都是在java堆中申請的,是以垃圾收集的區域就是對java堆和方法區的記憶體區域進行gc。

垃圾收集器的主要任務就是找出已經“消亡”的對象,将其标記并清除其說用記憶體的過程,如何判斷某個對象已經“消亡”,不同的虛拟機有不同的判斷政策

引用計數(reference counting)算法的基本思想就是:給每個對象添加一個引用計數器,每當有一個地方對該對象進行了引用,引用計數器就加1;引用失效後就減1;當引用計數器為0時,就表示沒有任何地方引用了該對象,這可以認為該對象已經“消亡”了。

雖然引用計數算法思想簡單,效率也很高,但是java虛拟機并沒有用到該算法标記“消亡”對象,因為當出現循環引用的時候,表現就不是那麼好了。我們可以編寫測試代碼測試并看gc資訊看看java虛拟機到底有沒有用該算法。

代碼示例中,建立了兩個對象obja,objb,然後通過obja.instance = objb,objb.instance = obja讓他們互相引用,然後将obja、objb都置為空,将會觸發gc,我們可以通過-xx:+printgcdetails讓java虛拟機在發生gc後列印出gc的具體資訊,

代碼片運作時的vm參數為-xmx20m -xms20m -xx:+printgcdetails

運作程式,可看到如下列印結果:

在分析結果前,先對gc的内容先做一個介紹:

1、gc日志的第一行[gc [psyounggen說明了在新生代發生了gc(minor gc),這裡也可以看出,目前的hotspot虛拟機采用的是parallel scavenge(ps)垃圾收集器 後面的4340k-&gt;256k代表gc前後的新生代記憶體區域的變化,這裡從4340k變到256k,說明虛拟機進行了垃圾回收,後面的(5952k)代表新生代的記憶體區域大小,4340k-&gt;256k(19648k)這裡的括号内的19648k代表新生代和年老代的記憶體大小。之後的0.0009373 secs代表的是gc所用的事件。 2、gc日志的第二行[full gc (system)表示系統觸發的一次full gc,也就是代碼中system.gc();所引起的gc,一次full gc會對java堆中的所有區域進行gc(新生代、年老代、永久代),是以後面的psyounggen(新生代)、psoldgen(年老代)、pspermgen(永久帶)顯示了各區域的gc情況,我們可以看到psyounggen: 256k-&gt;0k(5952k),新生代經過full gc後,全被清空了。 3、後面的heap堆顯示了各區域的最終使用情況 從最後的full gc (system) [psyounggen: 256k-&gt;0k(5952k)]可以看到,新生代中的記憶體全被gc了,是以說,hotspot并沒有用引用計數算法來對“消亡”對象進行gc。

現在一般的垃圾收集器都是用該算法(gc root tracing)來判斷對象是否“消亡”,該算法的基本思想就是:通過一組稱為“gc roots”的對象作為根節點,然後從這些根節點向下搜尋,搜尋所走過的路徑稱為引用鍊(reference chain),當一個對象到根節點之間沒有任何一條引用鍊的話,就認為該對象已經“消亡”,如下圖所示:

可以作為gc roots的對象包括:

1. 虛拟機棧(棧幀中的本地變量表)中的引用的對象

2. 方法區中 的類靜态屬性引用的對象

3. 方法區中的常量引用的對象

4. native方法引用的對象

任何判斷對象是否消亡都是通過引用來判斷,引用以前的定義是:如果reference類型的資料中存儲的數值代表的是另一塊記憶體區域的起始位址的話,就稱這塊記憶體代表一個引用