詳解常見的垃圾收集器
常見的垃圾收集器分為序列、吞吐量優先和響應時間優先三種。
序列:Serial
這是1.8 預設的GC器 ,主要設定的引數為:
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC
新生複製,老年標記整理
-XX:+UseAdaptiveSizePolicy
自適應調整新生代大小
-XX:GCTimeRatio=ratio
公式 1 / (1 + ratio) ratio預設值是99 ,也就是工作100分鐘內,只有1分鐘可以用於垃圾回收。如果達不到整個目標,ParallelGC會調增大堆的大小, 垃圾回收次數減少 ,以此來提高吞吐量。一般ratio設定為19。
-XX:MaxGCPauseMillis=ms
最大暫停時間也就是垃圾回收的時間,預設200ms
-XX:ParallelGCThreads=n
控制垃圾回收執行緒數量
工作流程與序列的區別是開啟多個垃圾回收執行緒來回收,數量由電腦的CPU核數決定,同樣使用者執行緒被阻塞。特點是多執行緒收集,讓單位時間內STW時間最短 即收集次數少時間可以長點,比如一小時內2次,一次0.2秒。
設定的引數為:
-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld --> CMS工作在老年代,使用標記清除演算法。ParNew工作在新生地,ParNew是Serial的多執行緒版本。但CMS有時候會發生併發失敗問題,這時候老年代垃圾回收器變為SerialOld 。
-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads:併發執行緒數一般設定為並行執行緒數的1/4,比如4核就設定成1。1個執行緒來做垃圾回收,另外3個繼續執行使用者執行緒。
-XX:CMSInitiatingOccupancyFraction=percent 執行CMS回收的記憶體佔比,值越小執行垃圾回收時機越早。
-XX:+CMSScavengeBeforeRemark 在重新標記前做一些新生代的垃圾回收。因為重新標記時,新生代的物件會引用老年代的物件,標記時需要掃描整個堆,然後通過新生代引用掃描到老年代物件並作可達性分析。這種場景下新生代物件非常多並且很多會作為垃圾物件被回收,再根據新生代物件引用找到老年代物件;相當於在回收之前多做了無用的查詢,這時可以使用這個引數,使用新生代存活物件變少,減輕重新標記的壓力。
工作流程是假設4核CPU並行執行4個執行緒。老年代記憶體不足,使用者執行緒在安全點停下來了。先進行初始標記,標記一些GCroots物件,這時候使用者執行緒被阻塞。下一步是併發標記,使用者執行緒和垃圾回收執行緒併發執行。第三步是重新標記,因為併發標記時使用者執行緒繼續執行,可能會產生新的物件,或者改變物件的一些引用。最後是併發清理,但這次清理不能回收同時產生的垃圾物件(浮動垃圾),浮動垃圾只能等到下一次垃圾回收時再清理,使用上面第三個引數調整。
CMS使用的標記清楚演算法,自然會產生大量記憶體碎片。將來分配物件時,當新生代記憶體不夠時,老年代記憶體由於碎片過多也不足,就會造成併發失敗,這時候垃圾回收器會退化為SerialOld,垃圾回收時間會劇增。