JVM相關參數介紹
阿新 • • 發佈:2017-09-02
再處理 執行 連接 變化 觸發 out jmap 需要 介紹 JVM性能調優:
JVM內存模型及垃圾收集算法
1.根據Java虛擬機規範,JVM將內存劃分為:
- New(年輕代)
- Tenured(年老代)
- 永久代(Perm)
- 年輕代(New):年輕代用來存放JVM剛分配的Java對象
- 年老代(Tenured):年輕代中經過垃圾回收沒有回收掉的對象將被Copy到年老代
- 永久代(Perm):永久代存放Class、Method元信息,其大小跟項目的規模、類、方法的量有關,一般設置為128M就足夠,設置原則是預留30%的空間
- Eden:Eden用來存放JVM剛分配的對象
- Survivor1
- Survivro2:兩個Survivor空間一樣大,當Eden中的對象經過垃圾回收沒有被回收掉時,會在兩個Survivor之間來回Copy,當滿足某個條件,比如Copy次數,就會被Copy到Tenured。顯然,Survivor只是增加了對象在年輕代中的逗留時間,增加了被垃圾回收的可能性。
- Serial算法(單線程)
- 並行算法
- 並發算法
- 當年輕代內存滿時,會引發一次普通GC,該GC僅回收年輕代。需要強調的時,年輕代滿是指Eden代滿,Survivor滿不會引發GC
- 當年老代滿時會引發Full GC,Full GC將會同時回收年輕代、年老代
- 當永久代滿時也會引發Full GC,會導致Class、Method元信息的卸載
- JVM98%的時間都花費在內存回收
- 每次回收的內存小於2%
- 每次垃圾回收的時間越來越長,由之前的10ms延長到50ms左右,FullGC的時間也有之前的0.5s延長到4、5s
- FullGC的次數越來越多,最頻繁時隔不到1分鐘就進行一次FullGC
- 年老代的內存越來越大並且每次FullGC後年老代沒有內存被釋放
- Visual VM
- IBM HeapAnalyzer
- JDK 自帶的Hprof工具
- 線程池:解決用戶響應時間長的問題
- 連接池
- JVM啟動參數:調整各代的內存比例和垃圾回收算法,提高吞吐量
- 程序算法:改進程序邏輯算法提高性能
- corePoolSize:核心線程數(最新線程數)
- maximumPoolSize:最大線程數,超過這個數量的任務會被拒絕,用戶可以通過RejectedExecutionHandler接口自定義處理方式
- keepAliveTime:線程保持活動的時間
- workQueue:工作隊列,存放執行的任務
- SynchronousQueue: 一個無容量的等待隊列,一個線程的insert操作必須等待另一線程的remove操作,采用這個Queue線程池將會為每個任務分配一個新線程
- LinkedBlockingQueue : 無界隊列,采用該Queue,線程池將忽略 maximumPoolSize參數,僅用corePoolSize的線程處理所有的任務,未處理的任務便在LinkedBlockingQueue中排隊
- ArrayBlockingQueue: 有界隊列,在有界隊列和 maximumPoolSize的作用下,程序將很難被調優:更大的Queue和小的maximumPoolSize將導致CPU的低負載;小的Queue和大的池,Queue就沒起動應有的作用。
- 以SynchronousQueue作為參數,使maximumPoolSize發揮作用,以防止線程被無限制的分配,同時可以通過提高maximumPoolSize來提高系統吞吐量
- 自定義一個RejectedExecutionHandler,當線程數超過maximumPoolSize時進行處理,處理方式為隔一段時間檢查線程池是否可以執行新Task,如果可以把拒絕的Task重新放入到線程池,檢查的時間依賴keepAliveTime的大小。
- Mysql默認支持100個鏈接,所以每個連接池的配置要根據集群中的機器數進行,如有2臺服務器,可每個設置為60
- initialSize:參數是一直打開的連接數
- minEvictableIdleTimeMillis:該參數設置每個連接的空閑時間,超過這個時間連接將被關閉
- timeBetweenEvictionRunsMillis:後臺線程的運行周期,用來檢測過期連接
- maxActive:最大能分配的連接數
- maxIdle:最大空閑數,當連接使用完畢後發現連接數大於maxIdle,連接將被直接關閉。只有initialSize < x < maxIdle的連接將被定期檢測是否超期。這個參數主要用來在峰值訪問時提高吞吐量。
- initialSize是如何保持的?經過研究代碼發現,BasicDataSource會關閉所有超期的連接,然後再打開initialSize數量的連接,這個特性與minEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis一起保證了所有超期的initialSize連接都會被重新連接,從而避免了Mysql長時間無動作會斷掉連接的問題。
- GC的時間足夠的小
- GC的次數足夠的少
- 發生Full GC的周期足夠的長
- 更大的年輕代必然導致更小的年老代,大的年輕代會延長普通GC的周期,但會增加每次GC的時間;小的年老代會導致更頻繁的Full GC
- 更小的年輕代必然導致更大年老代,小的年輕代會導致普通GC很頻繁,但每次的GC時間會更短;大的年老代會減少Full GC的頻率
- 如何選擇應該依賴應用程序對象生命周期的分布情況:如果應用存在大量的臨時對象,應該選擇更大的年輕代;如果存在相對較多的持久對象,年老代應該適當增大。但很多應用都沒有這樣明顯的特性,在抉擇時應該根據以下兩點:(A)本著Full GC盡量少的原則,讓年老代盡量緩存常用對象,JVM的默認比例1:2也是這個道理 (B)通過觀察應用一段時間,看其他在峰值時年老代會占多少內存,在不影響Full GC的前提下,根據實際情況加大年輕代,比如可以把比例控制在1:1。但應該給年老代至少預留1/3的增長空間
- -XX:HeapDumpPath
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:/usr/aaa/dump/heap_trace.txt
- -XX:+HeapDumpOnOutOfMemoryError
JVM相關參數介紹