jvm學習-垃圾收集

如何判斷對象是否須要回收

  • 引用計數算法:有引用就+1,引用失效就-1, 這種算法實現簡單,判斷效率也高,可是它很難解決對象之間的互相引用問題,A引用B,B引用A,可是A、B都沒有被使用了,這種算法回收不了。
  • 可達性分析算法:經過一系列的GC ROOTS做爲起始點,從這些起始點向下搜索,當一個對象不可達時證實此對象不可用,GC ROOTS對象的種類:虛擬機棧中引用的對象、方法區中類靜態屬性引用的對象、方法區中常量引用、本地方法棧中引用對象

        無論什麼算法都跟引用有關,Java裏面有下面四種引用由強到弱:java

  • 強引用:代碼中廣泛存在,相似Object obj = new Object(); 垃圾回收確定不會回收
  • 軟引用:對象還有用,但又不是必須的,系統將要發生內存溢出時回收,SoftReference類實現軟引用
  • 弱引用:也是非必須的對象,垃圾收集器下次工做會回收,WeakReference類來實現弱引用
  • 虛引用:最弱的一種關係,徹底不影響對象的生存時間,也沒法經過虛引用來取得一個對象實例,爲一個對象設置虛引用的惟一目的就是能在這個對象被回收時收到一個系統通知。

收集算法

  • 標記-清除:先標記出須要回收的對象,統一回收被標記的對象,容易產生內存碎片,效率也不高

        

  • 複製:爲了解決效率問題,把內存分開, 只是用其中的一部分,垃圾回收的時候把存活下的對象負責到另外一部分,而後把使用過的空間一次性清理掉, 年輕代98%的對象都是須要回收的,因此內存分配的時候不須要1:1,而是分紅eden區和兩塊存活區,每次把eden和一塊存活區負責到另外一塊存活區,HotSpot虛擬機推薦用8:1,因此一塊存活取空閒着只會浪費10%,固然若是存活的對象多於這10%,將直接進入老年代。

        

  • 標記整理:年老代存活對象比例較大,若是用複製算法就會進行較多的複製操做,效率低下,而且複製算法須要浪費一部分空間,因此這種算法不適合年老代,提出另一種算法標記整理,標記部分跟標記清除算法同樣,整理階段是讓存活的對象都向一端移動,而後直接清理掉邊界之外的內存。

        

  • 分代收集算法:根據對象存活週期不一樣將內存分幾塊,根據每塊的特色使用不一樣的收集算法

        

垃圾回收器

內存回收的具體實現,用一些線程模型結合上面算法實現了多種垃圾回收器,以下圖:算法

       

存在連線能夠搭配使用,目前沒有萬能的回收器,只能組合使用服務器

  • 串行收集serial:工做線程都停下來,一個線程去完成垃圾回收,複製算法
  • serial Old:    同上,年老代使用標記-整理算法

       

  • 並行收集ParNew: serial收集器的多線程版本,其餘參數配置回收策略都與serial同樣,看上面的連線只有ParNew收集器和serial收集器能跟CMS合用
  • Parallel Scavenge: 採用複製算法,也是並行收集,它更關注如何控制吞吐量,吞吐量=運行用戶代碼時間/總時間,它更適合後臺運算的程序。
  • Parallel Old: Parallel Scavenge老年代版本,採用多線程和標記整理算法

        

  • CMS:CMS偏響應時間Parallel偏吞吐量,過程,

                    初始標記(要停用戶線程):標記一下GC Roots能直接關聯到的對象
                    併發標記:進行GC Roots Tracing的過程
                    從新標記(停用戶線程),修正併發標記期間用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄
                    併發清除:基於標記清除算法作的,因此這階段就是清除,
            耗時最長的是能夠與用戶線程一塊兒運行的併發標記和併發清除階段。多線程

        

  • G1:它的目標是做爲一款服務器的垃圾收集器,所以,它在吞吐量和停頓控制上,預期要優於 CMS 收集器。與 CMS 收集器相比,G1 收集器是基於標記-壓縮算法的(使用G1後內存空間不是連續的,由一些Region組成,經過預測要回收的Region來進行部分回收,2-8理論)。所以,它不會產生空間碎片,也沒有必要在收集完成後,進行一次獨佔式的碎片整理工做。G1 收集器還能夠進行很是精確的停頓控制。它可讓開發人員指定當停頓時長爲 M 時,垃圾回收時間不超過 N。

這裏的並行、併發的概念:
        並行(parallel):多個線程同時工做,可是用戶線程任然處於等待狀態
        併發(Concurrent):用戶線程與垃圾收集器線程同時執行。併發

理解GC日誌

        

[GC、[Full GC表示停頓類型,[DefNew、[Tenured、[Perm是發生區域,這裏的區域名稱與使用的垃圾收集器密切相關,方括號裏面的3324K->152K(3712K)表示GC以前該內存已使用容量->GC以後該內存使用容量(該內存區域總容量),方括號外面的3324K-152K(11904K)表示GC以前Java堆已使用容量->GC以後Java堆使用容量(Java堆總容量),最後0.0025925secs表示該內存區域GC使用時間。優化

垃圾收集器參數

-XX:+<option> 啓用選項
-XX:-<option> 不啓用選項
-XX:<option>=<number>
-XX:<option>=<string>spa

-XX:+UseSerialGC Jvm運行在Client模式下的默認值,打開此開關後,使用Serial + Serial Old的收集器組合進行內存回收
-XX:+UseParNewGC 打開此開關後,使用ParNew + Serial Old的收集器進行垃圾回收
-XX:+UseConcMarkSweepGC 使用ParNew + CMS +  Serial Old的收集器組合進行內存回收,Serial Old做爲CMS出現「Concurrent Mode Failure」失敗後的後備收集器使用。
-XX:+UseParallelGC Jvm運行在Server模式下的默認值,打開此開關後,使用Parallel Scavenge +  Serial Old的收集器組合進行回收
-XX:+UseParallelOldGC 使用Parallel Scavenge +  Parallel Old的收集器組合進行回收
-XX:SurvivorRatio 新生代中Eden區域與Survivor區域的容量比值,默認爲8,表明Eden:Subrvivor = 8:1
-XX:PretenureSizeThreshold 直接晉升到老年代對象的大小,設置這個參數後,大於這個參數的對象將直接在老年代分配
-XX:MaxTenuringThreshold 晉升到老年代的對象年齡,每次Minor GC以後,年齡就加1,當超過這個參數的值時進入老年代
-XX:UseAdaptiveSizePolicy 動態調整java堆中各個區域的大小以及進入老年代的年齡
-XX:+HandlePromotionFailure 是否容許新生代收集擔保,進行一次minor gc後, 另外一塊Survivor空間不足時,將直接會在老年代中保留
-XX:ParallelGCThreads 設置並行GC進行內存回收的線程數
-XX:GCTimeRatio GC時間佔總時間的比列,默認值爲99,即容許1%的GC時間,僅在使用Parallel Scavenge 收集器時有效
-XX:MaxGCPauseMillis 設置GC的最大停頓時間,在Parallel Scavenge 收集器下有效
-XX:CMSInitiatingOccupancyFraction 設置CMS收集器在老年代空間被使用多少後出發垃圾收集,默認值爲68%,僅在CMS收集器時有效,-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSCompactAtFullCollection 因爲CMS收集器會產生碎片,此參數設置在垃圾收集器後是否須要一次內存碎片整理過程,僅在CMS收集器時有效
-XX:+CMSFullGCBeforeCompaction 設置CMS收集器在進行若干次垃圾收集後再進行一次內存碎片整理過程,一般與UseCMSCompactAtFullCollection參數一塊兒使用
-XX:+UseFastAccessorMethods 原始類型優化
-XX:+DisableExplicitGC 是否關閉手動System.gc
-XX:+CMSParallelRemarkEnabled 下降標記停頓
-XX:LargePageSizeInBytes 內存頁的大小不可設置過大,會影響Perm的大小,-XX:LargePageSizeInBytes=128m
-XX:+PrintFlagsFinal 可查看jdk參數的默認值
相關文章
相關標籤/搜索