【聲明】 html
歡迎轉載,但請保留文章原始出處→_→ 算法
生命壹號:http://www.cnblogs.com/smyhvae/服務器
文章來源:http://www.cnblogs.com/smyhvae/p/4748313.html
多線程
本文主要內容:架構
零、堆的回顧:併發
新生代中的98%對象都是「朝生夕死」的,因此並不須要按照1:1的比例來劃份內存空間,而是將內存分爲一塊比較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。當回收時,將Eden和Survivor中還存活着的對象一次性地複製到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。HotSpot虛擬機默認Eden和Survivor的大小比例是8:1,也就是說,每次新生代中可用內存空間爲整個新生代容量的90%(80%+10%),只有10%的空間會被浪費。jvm
固然,98%的對象可回收只是通常場景下的數據,咱們沒有辦法保證每次回收都只有很少於10%的對象存活,當Survivor空間不夠用時,須要依賴於老年代進行分配擔保,因此大對象直接進入老年代。性能
堆的結構以下圖所示:網站
垃圾收集器:線程
若是說收集算法時內存回收的方法論,那麼垃圾收集器就是內存回收的具體實現。
雖然咱們在對各類收集器進行比較,但並不是爲了挑出一個最好的收集器。由於直到如今位置尚未最好的收集器出現,更加沒有萬能的收集器,因此咱們選擇的只是對具體應用最合適的收集器。
1、串行收集器:Serial收集器
新生代、老年代都會使用串行回收
新生代複製算法
老年代標記-整理
總結:Serial收集器對於運行在Client模式下的虛擬機來講是一個很好的選擇。
這個收集器是一個單線程的收集器,但它的單線程的意義並不只僅說明它只會使用一個CPU或一條收集線程去完成垃圾收集工做,更重要的是在它進行垃圾收集時,必須暫停其餘全部的工做線程,直到它收集結束。收集器的運行過程以下圖所示:
2、並行收集器:
一、ParNew收集器:
新生代並行
老年代串行
二、Parallel Scanvenge收集器:
三、Parallel Old收集器:
以下圖所示:
各類參數設置:
最大停頓時間,單位毫秒
GC盡力保證回收時間不超過設定值
0-100的取值範圍
垃圾收集時間佔總時間的比
默認99,即最大容許1%時間作GC
注:這兩個參數是矛盾的。由於停頓時間和吞吐量不可能同時調優。咱們一方買但願停頓時間少,另一方面但願吞吐量高,其實這是矛盾的。由於:在GC的時候,垃圾回收的工做總量是不變的,若是將停頓時間減小,那頻率就會提升;既然頻率提升了,說明就會頻繁的進行GC,那吞吐量就會減小,性能就會下降。
吞吐量:CPU用於用戶代碼的時間/CPU總消耗時間的比值,即=運行用戶代碼的時間/(運行用戶代碼時間+垃圾收集時間)。好比,虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。
注2:以上全部的收集器當中,當執行GC時,都會stop the world,可是下面的CMS收集器卻不會這樣。
3、CMS收集器:
CMS收集器(Concurrent Mark Sweep:併發標記清除)是一種以獲取最短回收停頓時間爲目標的收集器。適合應用在互聯網站或者B/S系統的服務器上,這類應用尤爲重視服務器的響應速度,但願系統停頓時間最短。
注:這裏的併發指的是與用戶線程一塊兒執行。
二、CMS收集器運行過程:(着重實現了標記的過程)
(1)初始標記
根能夠直接關聯到的對象
速度快
(2)併發標記(和用戶線程一塊兒)
主要標記過程,標記所有對象
(3)從新標記
因爲併發標記時,用戶線程依然運行,所以在正式清理前,再作修正
(4)併發清除(和用戶線程一塊兒)
基於標記結果,直接清理對象
整個過程以下圖所示:
其中,初始標記和從新標記時,須要stop the world。
整個過程當中耗時最長的是併發標記和併發清除,這兩個過程均可以和用戶線程一塊兒工做。
打印GC日誌舉例以下:
三、CMS收集器特色:
(1)儘量下降停頓
(2)會影響系統總體吞吐量和性能
好比,在用戶線程運行過程當中,分一半CPU去作GC,系統性能在GC階段,反應速度就降低一半
(3)清理不完全
由於在清理階段,用戶線程還在運行,會產生新的垃圾,沒法清理
(4)由於和用戶線程一塊兒運行,不能在空間快滿時再清理
-XX:CMSInitiatingOccupancyFraction設置觸發GC的閾值
若是不幸內存預留空間不夠,就會引發concurrent mode failure
咱們來看一下concurrent mode failure的日誌:
碰到上圖中的狀況,咱們須要使用串行收集器做爲後備。
四、既然標記清除算法會形成內存空間的碎片化,CMS收集器爲何使用標記清除算法而不是使用標記整理算法:
答案:
CMS收集器更加關注停頓,它在作GC的時候是和用戶線程一塊兒工做的(併發執行),若是使用標記整理算法的話,那麼在清理的時候就會去移動可用對象的內存空間,那麼應用程序的線程就頗有可能找不到應用對象在哪裏。
爲了解決碎片的問題,CMS收集器會有一些整理上的參數,接下來就來說這個。
五、整理時的各類參數:
Full GC後,進行一次整理。整理過程是獨佔的,會引發停頓時間變長
設置進行幾回Full GC後,進行一次碎片整理
設定CMS的線程數量
4、GC參數的整理:
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:設置eden區大小和survivior區大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用並行收集器
-XX:+UseParallelGC :新生代使用並行回收收集器
-XX:+UseParallelOldGC:老年代使用並行回收收集器
-XX:ParallelGCThreads:設置用於垃圾回收的線程數
-XX:+UseConcMarkSweepGC:新生代使用並行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:設定CMS的線程數量
-XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少後觸發
-XX:+UseCMSCompactAtFullCollection:設置CMS收集器在完成垃圾收集後是否要進行一次內存碎片的整理
-XX:CMSFullGCsBeforeCompaction:設定進行多少次CMS垃圾回收後,進行一次內存壓縮
-XX:+CMSClassUnloadingEnabled:容許對類元數據進行回收
-XX:CMSInitiatingPermOccupancyFraction:當永久區佔用率達到這一百分比時,啓動CMS回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到達閥值的時候,才進行CMS回收
最後的總結:
爲了減輕GC壓力,咱們須要注意些什麼?
參考連接: