Java內存模型和GC基礎

一、java內存模型java

  1.一、運行時數據區分爲五大塊算法

    一、程序計數器,應對中斷、時間片執行,記錄當前執行到的字節碼位置,以便後續繼續執行;緩存

    二、虛擬機棧,即平時所謂的棧區,存儲局部變量、動態連接、方法出口等;安全

    三、本地方法棧,爲native方法服務,基本同虛擬機棧,在Hotspot中虛擬機棧和本地方法棧被合併;優化

    四、方法區,存儲類加載信息、常量、靜態變量、運行時常量池;spa

    五、堆區,GC主要工做區,java中存放實例對象的地方。.net

  綜上,其實份三大部分,程序計數,棧區(服務java方法-虛擬機棧,服務native方法-本地方法棧),方法區-運行時數據,堆區-對象。線程

  

二、GC基礎(針對hotspot)對象

  2.一、判斷對象死亡blog

  1)引用計數算法(無主流虛擬機使用):爲對象添加引用計數器,每個地方引用,計算加1,引用失效則減1,爲了即再也不使用。優勢是實現簡單,斷定效率高,存在問題-沒法解決對象間互相引用問題:

    object  A,B包含instance,

    A.instance = B; // B_count = 1 , A_count = 1

    B.instance = A;//B_count = 2, A_count = 2

    A = null; //A_count = 1

    B = null; //B_count = 1

  A、B已經沒法被引用到,可是計數仍然爲1,沒法被清除。

  2)可達性分析:經過一系列GC Roots向下搜索,搜素路徑即引用鏈,在搜索鏈上的可達,不然不可達。

    GC Roots人羣:一、虛擬機棧中引用對象,如局部變量;二、方法區中類的靜態屬性對象;三、方法區中常量引用對象;四、本地方法棧中Native方法引用對象。

    引用分類:一、強引用,new出來的對象,GC不敢碰;

         二、軟引用,有用但非必需,GC通常不碰,在要內存溢出時,會進行垃圾第二次回收,此時纔會清除軟引用,提供了SoftReference類(可用做緩存?);

         三、弱引用,非必需對象,比軟引用更軟,活不過第二集就是他,在GC下次運行時,無論內存夠不夠都會被清理,提供WeakReference類;

         四、虛引用(幽靈引用、幻像引用),最弱。有他沒他不影響對象生存時間,沒法經過他獲得對象實例,惟一做用:在被收集器回收時,會獲得一個通知。提供PhantomReference類;

  3)finalize()方法,GC可達性分析後,不在引用鏈上的對象,有一次執行finalze()方法自救的機會(僅執行一次),虛擬機判斷有必要finalze()後,會把對象放入F-Queue隊列中,並建立一個低優先級線程Finalizer去執行該方法。

  4)提一下,方法區也有垃圾回收,即永久代的回收,如常量池無引用對象的回收。

  2.二、垃圾收集算法

  2.2.1 標記-清除算法:兩個階段,標記和清除;兩個問題,效率和空間,標記算法和清除算法自己效率不高(循環遍歷),另外清除後存在大量不連續內存碎片,分配較大對象時,無內存可用。

  2.2.2 複製算法,基本思想:把內存分爲兩個部分,一部份用完了,就把已存活的對象依次複製到另外一半上去。算法簡單高效,也無碎片問題。缺點是費錢,好好的內存,利用率只有一半。

  2.2.3 標記-整理算法:複製算法若是每次清理都有不少對象保留,那麼複製一次到另外一邊的內存效率更低。針對這種狀況,仍是先標記,只是在清理時不是直接幹掉無用對象,而是把存活對象向內存的一端移動,最後直接清理邊界外的內存。       

  2.三、年代劃分

  1)根據IBM研究,java中的對象98%時朝生夕死,因此死的比較快的區域叫新生代,新生代中一部分比較頑強在經歷屢次GC(hotspot默認15次)後還沒被回收,就會被分入老年代。

  正經講就是java堆中,根據對象存活週期的不一樣,對象被分爲新生代和老年代。根據這個特色垃圾收集也採用分代收集算法,複製算法效率高,可是複製對象成本高,適合新生代中在每次收集時大批對象死去,只需複製少許對象就可完成收集。而老年代對象成活率高,通常採用標記-清除,或者標記整理算法。

  2)新生代延伸,上面說新生代採用複製算法,可是2.2.2中也說了複製算法空間利用率低。所以如今把新生代進一步劃分:一塊較大的Eden區,和兩塊較小的Survivor區。

  由於在新生代空間,每次收集時,只會有少許對象存活,這樣1:1劃分使用空間和複製空間就沒有意義。實際中新生代每次使用Eden和其中一塊Survivor存儲對象,垃圾收集時,再把存活的對象複製到另外一塊Survivor空間。Hotspot中兩個區域的比例默認8:1,即每次新生代有80%+10%的內存空間存儲新生代,只有10%被閒置。

  3)上面90%使用率的狀況適合於絕大多數對象回收場景,可是在某些狀況下,一次垃圾回收時存活的對象超過了10%新生代空間,即一塊Survivor空間不夠用,這時只能依賴其餘內存(老年代),新生代沒法容納的存活對象將直接進入老年代,這種行爲即分配擔保。

三、HotSpot算法實現

  3.一、枚舉根節點

  即上文提到過的可達性分析,符合GC Roots條件的變量也太多(常量、類靜態屬性、本地變量表),所以引入了安全點的概念,Sefepoint會選取指令序列複用的的點(每條指令執行都很快,若是出現某些指令長時間執行,最明顯的就是指令序列複用,如循環跳轉、方法調用等)。可達性分析時就會從這些安全點來遍歷。

  另外要提的是-Stop The World!  GC在進行可達性分析時,整個執行系統都會被暫停在一點上,由於一邊進行對象引用關係分析,一遍還運行程序改變引用關係的話,就無從分析了。這個時GC卡頓的根源,也是各類垃圾收集器優化的重點。

  3.二、垃圾收集器

        

 

 

 

 

  to be continue!!!

 

 

參考:  一、https://blog.csdn.net/u011080472/article/details/51324422 

相關文章
相關標籤/搜索