天天看點

java:垃圾~判定&&回收,Stop the World~~!

垃圾回收算法:

引用計數法:

        對象頭部維護一個count計算引用次數,當為0的時候判斷可以作為垃圾清除;

        問題:無法區分引用類型,無法解決循環引用(會死鎖永遠無法garbage collection)

可達性分析算法:

        通過gc root向下周遊整個對象引用圖,這些對應都是存活對象,那麼剩下來的就是無法和gc root建立引用鍊的都是無用對象(是以就算存在互相引用,這兩個引用的對應都是無法到gc root存在引用鍊的,是以都是垃圾對象);也就是說可達性分析和引用計數出發點不同,前者判斷存活,剩下的全是要篩選的垃圾,前者相反;

        // 什麼可以作為gc root

是以JVM的垃圾回收采用可達性分析算法判斷對象是否是垃圾

垃圾回收具體實作:

标記清除算法:給需要回收的地方加上标記然後清除,效率高,但是會有大量記憶體碎片;

複制算法:專門解決記憶體碎片問題,将記憶體一分為二,左邊回收将非垃圾複制到右邊然後集體回收;不會産生記憶體碎片;但是記憶體變小,因為始終隻有一半記憶體可用,一半為空。

标記整理算法:将需要清除的先标記,然後将垃圾内容統一移到最左邊或最右邊然後集中清理;不會産生記憶體碎片,但是大量修改對象記憶體引用位址,效率比複制算法低很多;

整合三種算法之長:分代收集算法,也就是JVM采用的回收垃圾算法

                                                                          年輕代占比:                                              

 1/3 (其中Eden(死亡伊甸園 百分之98的對象會在這裡GG)占比 8/10  Survivor區中兩塊: from占比 1/10 to占比 1/10)                                              

                                                                          老年代占比:

                                                 2/3 (垃圾回收算法采用标記整理算法)

年輕代回收:(Minor GC)

      存活區(Survivor的from和to):每次來自Eden和from的存活采用複制算法儲存到to區然後整體清除回收Eden和from區;

      采用複制算法原因:避免記憶體碎片是以排除标記清除,考慮效率和存活的對象比較少,使用複制算法;

老年代回收:(Major GC)

      采用标記整理算法;過程采用Stop The World,記憶體越大,STW時間越長;

       原因:老年代的記憶體較大,如果要用複制算法隻能使用一半過于浪費,而且過多的複制效率較低,又要避免大量記憶體碎片,是以使用标記整理算法;

為什麼要有Survivor區?

   相當于Eden區和老年代的緩沖區,因為并不是進入Survivor區的就能成為老年代的對象,很有可能在接下來的垃圾回收裡回收掉,大多數情況下在Survivor存活15次及以上才能進入老年代;是以Survivor區的目的是為了減少老年代GC的壓力;

對象進入老年代的情況?

   to區滿了,那就全部進老年代;在Survivor區存活時間超過15次可以直接進入老年代;survivor區相同年齡對象大小總和超過survivor區的一半則一起進入老年代(稱作動态年齡對象);連續記憶體空間的大對象直接進入老年代,無論是否是“朝生夕死”對象,目的是為了避免survivor倆區之間的大量複制;(如果系統存在大量這樣的對象,就會多次觸發Major GC,需要注意)