jvm調優思路及調優案例

jvm調優思路及調優案例我們說jvm調優,其實就是不斷測試調整jvm的運行參數 , 盡可能讓對象都在新生代(Eden)里分配和回收,盡量別讓太多對象頻繁進入老年代,避免頻繁對老年代進行垃圾回收,同時給系統充足的內存大??,避脧T律搗鋇慕欣厥?。從而減少STW(stop the world)的時間 。
調優思路項目運行內存分析我們運行應用程序時,一般會設置一些jvm參數,比如堆內存大小 , 年輕代大小 , Eden和Survivor的比例,老年代大?。?大對象的閾值,大齡對象進入老年代的閾值等 。
而設置這些jvm參數,有2種方式:

  1. 通過物理內存分析設置,比如機器有8G內存,假設操作系統分配2-3G,元空間分配256M,堆分配4-5G 。
  2. 通過1設置之后,再通過分析具體的gc日志來調優 。
我們知道jvm有自己的運行時數據區(內存模型),其中堆大??,壹s岸閻械哪昵崠?、老年代的大小比例譀鲐重?,主要就是調整堆中的內存比例,運行時數據區(內存模型)圖,如下圖:
jvm調優思路及調優案例

文章插圖
具體思路1、分析年輕代對象增長的速率
可以執行命令 jstat -gc pid 1000 10 (每隔1秒執行1次命令,共執行10次) , 通過觀察EU(eden區的使用)來估算每秒eden大概新增多少對象,如果系統負載不高,可以把頻率1秒換成1分鐘,甚至10分鐘來觀察整體情況 。注意,一般系統可能有高峰期和日常期,所以需要在不同的時間分別估算不同情況下對象增長速率 。
2、Young GC的觸發頻率和每次耗時
知道年輕代對象增長速率我們就能推根據eden區的大小推算出Young GC大概多久觸發一次,Young GC的平均耗時可以通過 YGCT/YGC 公式算出,根據結果我們大概就能知道系統大概多久會因為Young GC的執行而卡頓多久 。
3、每次Young GC后有多少對象存活和進入老年代
這個因為之前已經大概知道Young GC的頻率,假設是每5分鐘一次,那么可以執行命令 jstat -gc pid 300000 10,觀察每次結果eden,survivor和老年代使用的變化情況 , 在每次gc后eden區使用一般會大幅減少 , survivor和老年代都有可能增長,這些增長的對象就是每次Young GC后存活的對象,同時還可以看出每次Young GC后進去老年代大概多少對象,從而可以推算出老年代對象增長速率 。
4、Full GC的觸發頻率和每次耗時
知道了老年代對象的增長速率就可以推算出Full GC的觸發頻率了,Full GC的每次耗時可以用公式 FGCT/FGC 計算得出 。
總結:盡量讓每次Young GC后的存活對象小于Survivor區域的50%,都留存在年輕代里 。盡量別讓對象進入老年代 。盡量減少Full GC的頻率 , 避免頻繁Full GC對JVM性能的影響 。
注意:對象進入老年代的幾種方式:
  1. 大對象
  2. 對象到達一定年齡閾值
  3. 動態對象年齡判斷(Young GC后的存活對象小于Survivor區域的50%)
調優案例案例準備這里準備了一個示例程序(demo鏈接) , 運行以后,我們采用上篇文章介紹到的jstat工具查看各個內存gc的情況 。
初始JVM參數:
-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=6 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly根據這些參數,我們知道大體的內存模型是這樣的:最快經過6s之后才會發生一次Young GC 。
jvm調優思路及調優案例

文章插圖
調優分析【jvm調優思路及調優案例】示例程序啟動后,我們調用測試類的test()方法:
@RunWith(SpringRunner.class)@SpringBootTest(classes={Application.class})// 指定啟動類public class ApplicationTests { @Bean public RestTemplate restTemplate() {return new RestTemplate(); } @Autowired private RestTemplate restTemplate; @Test public void test() throws Exception {for (int i = 0; i < 10000; i++) {String result = restTemplate.getForObject("http://localhost:8080/user/process", String.class);Thread.sleep(1000);} }}然后觀察整個過程前后,虛擬機的內存gc變化:
jvm調優思路及調優案例

文章插圖
發現不僅Young GC次數增多了,Full GC的次數也隨著增多,說明對象不僅增長得快,連進入老年代的時間挺快的 。

推薦閱讀