聊聊JVM怎麼調優(實戰)
這節我略去基礎部分了,不熟悉基礎的,可以看我之前的文章
一、堆內存大小和年輕代佔比
1、這個是個影響最大的配置,在機器配置允許的情況下,堆內存給的越大越好;另外,堆內存的最大和最小值一定要設置成一樣的,因為jvm堆內存擴容的時候會觸發full gc,元空間也一樣,最大內存和最小內存值設置成一樣的
2、年輕代的佔比一般來説是大一些比較好,因為這樣會減少young gc的次數(ZGC之前的回收器young gc都是STW的)
二、回收器應該怎麼去選擇
一般來説,現在的後端服務有兩種,一種是對延遲不是很敏感的,比如多數的數據處理、分析類型的應用(多為OLAP型),這種應用的GC回收器,一般是選擇### Parallel 和 Parallel Old,這哥兩都是以吞吐量為優先的垃圾回收器。另外一種應用是對延遲比較敏感的,一般應該選用G1。
!
《深入理解java虛擬機》這本書上説過,在內存比較小的情況下,應該選用CMS而不是G1,但是經過作者在各種場景和各種小內存情況下測試,G1都比CMS好了太多,所以作者從實際的角度出發,推薦在追求低延遲的場景下使用G1。
三、高併發場景(有難度的一個場景)
需要注意的是高併發的場景,這時候應該是去選擇低停頓而不是高吞吐量的回收器,因為ps回收器的這兩個哥們,在young gc和old gc的時候都是stw的,而G1的mixed gc的一些回收階段最少還是能夠和用户線程併發去執行的,這樣會減少stw的時間。在高併發之下,一定要想辦法去減少stw,因為在高併發的時候的由於gc而導致的stw,這時候java進程中只有gc線程在活動,而gc的線程優先級比較低,這樣的話,操作系統資源就更容易被分配去處理併發請求(注意線程優先級不僅僅是java的概念),導致gc線程被分配到的時間變少,然後stw時間進一步增加,然後導致請求進一步堆積,進而導致gc效率進一步降低和頻率進一步升高的惡性循環。
四、其他簡單一些規範
1、棧大小
jvm默認是1M,但是其實大多數情況下256K足矣,這樣可以減少StackOverFlow的概率
2、堆內存/元空間最大最小值設置為一樣
這是因為不論是堆內存還是元空間,在動態擴容的時候,都會出發full gc,這個原理有點類似於數組擴容。
3、OOM發生的時候dump日誌
這點就不必解釋太多了。
4、full gc前後dump
這一點要謹慎,因為dump其實是個很消耗資源的操作,僅僅用在測試環境,生產環境最好不要用。
5、線上嚴禁開jvm 的遠程debug
這也是個低級錯誤。
6、禁止顯式調用System.gc()
同上,也是低級錯誤,gc不要人為調用。
7、不要試圖通過參數將停頓時間控制的很短
這個是由於jvm的不可能三角所導致的,停頓時間非常短的時候,對應的gc的頻率就會增加,進而導致吞吐量降低。