聊聊JVM怎麼調優(實戰)

語言: CN / TW / HK

這節我略去基礎部分了,不熟悉基礎的,可以看我之前的文章

1、細説jvm(一)、jvm運行時的數據區域

2、細説jvm(二)、java對象創建過程

3、細説jvm(三)、對象創建的內存分配

4、細説jvm(四)、垃圾回收算法

5、細説jvm(五)、垃圾回收器入門

6、細説jvm(六)、垃圾回收器CMS詳解

7、細説jvm(七)、垃圾回收器G1

8、細説jvm(八)、垃圾回收器ZGC

一、堆內存大小和年輕代佔比

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的頻率就會增加,進而導致吞吐量降低。