JVM GC演算法以及調優
jvm的垃圾回收器是jvm的重要組成部分。GC負責著整個jvm執行時堆中物件的回收,保證jvm的效能。由於Java執行GC垃圾回收時會阻塞其他所有的執行緒,這樣是對使用者極不友好的,即對GC的優化重點是降低阻塞的時間,對GC的調優也就是對jvm的效能調優的重點。
jvm堆的記憶體模式(畫的比較簡陋,忘海涵)
jvm為堆記憶體劃分了幾塊區域如上圖:
最左邊的new generation是新生代,新生代分為3塊區域一個是eden區,還有兩個suvivor區。最右邊的是老年代區域。
例項化一個物件時
1. 絕大多數剛剛被建立的物件會存放在eden空間。
2. 在eden空間執行了第一次GC之後,存活的物件被移動到其中一個survivor空間。
3 .此後,在eden空間執行GC之後,存活的物件會被堆積在同一個survivor空間。
4. 當一個survivor空間飽和,還在存活的物件會被移動到另一個survivor空間。之後會清空已經飽和的那個survivor空間。
5. 在以上的步驟中重複幾次依然存活的物件,就會被移動到老年代。
從上面執行過程可以看出survivor區域必定有一塊是空的,用JVM監控工具可以觀察兩個survivor區域的狀況,如果兩個survivor區域都有物件,則說明此時jvm是有問題的。
GC常用演算法:
序列收集器(Serial GC)
最古老的垃圾回收演算法沒有之一,是以前執行在單核cpu的伺服器下 的。新生代、老年代都使用序列演算法回收。
演算法的第一步是標記老年代中依然存活物件。第二步是從頭開始檢查堆記憶體空間,並且只留下依然倖存的物件。最後一步,從頭開始,順序地填滿堆記憶體空間,並且將對記憶體空間分成兩部分:一個儲存著物件,另一個空著。在jvm下配置的引數是 -XX:+UseSerialGC
並行垃圾回收器(Parallel GC)
parallel GC可以看成是Serial GC的升級版,它是採用多執行緒的機制是執行GC操作,所以執行GC過程阻塞時間較短。新生代採用的是並行演算法,而老年代依然採用的是序列演算法。在jvm下配置的引數是 -XX:+UseParallelGC,是jvm預設的GC回收演算法。
併發標記掃描垃圾回收器(CMS收集器)
Concurrent Mark Sweep是應用程式執行緒和GC執行緒交替執行
使用的標記-清除演算法,併發階段會降低吞吐量。它經常被用在那些對於響應時間要求十分苛刻的應用之上。
老年代收集器。在jvm下配置的引數是 -XX:+UseConcMarkSweepGC
G1收集器
G1垃圾回收器適用於堆記憶體很大的情況,他將堆記憶體分割成不同的區域,並且併發的對其進行垃圾回收。G1也可以在回收記憶體之後對剩餘的堆記憶體空間進行壓縮。併發掃描標記垃圾回收器在STW情況下壓縮記憶體。G1垃圾回收會優先選擇第一塊垃圾最多的區域.在jvm下配置的引數是 -XX:+UseG1GC
根據應用場景的不同選擇不同的GC演算法是必要的。還有一些重要的引數,例如分配給堆的記憶體大小最大是多少 -Xmx引數,初始化是多少-Xms,一般我們將-Xmx與-Xms設定相同,避免jvm頻繁的變更堆記憶體的大小消耗cpu的效能;還有新生代的區域大小引數的配置-XX:NewRatio:3,一般配置的是2-3,這時新生代的記憶體大小=Xmx/NewRatio+1。
一般推薦的JVM引數