GC常用參數
- -Xmn -Xms -Xmx -Xss
年輕代 最小堆 最大堆 棧空間 - -XX:+UseTLAB
使用TLAB,默認打開 - -XX:+PrintTLAB
打印TLAB的使用情況 - -XX:TLABSize
設置TLAB大小 - -XX:+DisableExplictGC
System.gc()不管用 ,FGC - -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintHeapAtGC
- -XX:+PrintGCTimeStamps
- -XX:+PrintGCApplicationConcurrentTime (低)
打印應用程序時間 - -XX:+PrintGCApplicationStoppedTime (低)
打印暫停時長 - -XX:+PrintReferenceGC (重要性低)
記錄回收了多少種不同引用類型的引用 - -verbose:class
類加載詳細過程 - -XX:+PrintVMOptions
- -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
必須會用 - -Xloggc:opt/log/gc.log
- -XX:MaxTenuringThreshold
升代年齡,最大值15 - 鎖自旋次數 -XX:PreBlockSpin 熱點代碼檢測參數-XX:CompileThreshold 逃逸分析 標量替換 …
這些不建議設置
JVM調優第一步,瞭解JVM常用命令行參數
-
JVM的命令行參數參考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-
HotSpot參數分類
標準: - 開頭,所有的HotSpot都支持
非標準:-X 開頭,特定版本HotSpot支持特定命令
不穩定:-XX 開頭,下個版本可能取消
java -version
java -X
試驗用程序:
import java.util.List;
import java.util.LinkedList;
public class HelloGC {
public static void main(String[] args) {
System.out.println("HelloGC!");
List list = new LinkedList();
for(;;) {
byte[] b = new byte[1024*1024];
list.add(b);
}
}
}
查看默認參數
查看GC詳細信息
一條GC信息的詳細信息如下:
關於上圖中的Times含義:在linux中的times代表:
Heap Dump的含義
eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
後面的內存地址指的是,起始地址,使用空間結束地址,整體空間結束地址
調優實戰
調優前的基礎概念:
- 吞吐量:用戶代碼時間 /(用戶代碼執行時間 + 垃圾回收時間)
- 響應時間:STW越短,響應時間越好
所謂調優,首先確定,追求啥?吞吐量優先,還是響應時間優先?還是在滿足一定的響應時間的情況下,要求達到多大的吞吐量…
問題:
科學計算,吞吐量。數據挖掘,thrput。吞吐量優先的一般:(PS + PO)
響應時間:網站 GUI API (1.8 G1)
什麼是調優?
- 根據需求進行JVM規劃和預調優
- 優化運行JVM運行環境(慢,卡頓)
- 解決JVM運行過程中出現的各種問題(不完全等同於解決OOM的問題,因爲前面兩項也很重要)
併發:
- QPS
- TPS
淘寶雙11併發歷年最高54萬,據說12306併發比淘寶更高,號稱上百萬
調優,從規劃開始
-
調優,從業務場景開始,沒有業務場景的調優都是耍流氓
-
無監控(壓力測試,能看到結果),不調優(可以調整業務邏輯)
-
步驟:
- 熟悉業務場景(沒有最好的垃圾回收器,只有最合適的垃圾回收器)
- 響應時間、停頓時間 [CMS G1 ZGC] (需要給用戶作響應)
- 吞吐量 = 用戶時間 /( 用戶時間 + GC時間) [PS]
- 選擇回收器組合
- 計算內存需求(沒有一定之規,是經驗值。 1.5G -> 16G,突然卡頓了,爲啥?)
- 選定CPU(預算能買到的,當然是越高越好,CPU多核,可以多線程運行呀)
- 設定年代大小、升級年齡
- 設定日誌參數,這是Java虛擬機的參數,也可以在Tomcat裏面配置,貌似是在叫catalinaoptions裏面指定java日誌的參數。
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
5個日誌文件,循環產生。生產環境中的日誌參數一般這麼設置。
%t
是生成時間的意思。
- 或者每天產生一個日誌文件
- 觀察日誌情況
- 熟悉業務場景(沒有最好的垃圾回收器,只有最合適的垃圾回收器)
如何根據需求進行JVM規劃和預調優?
有人要問你,你應該選用多大的內存?什麼樣的垃圾回收器組合?你怎麼回答?
-
案例1:垂直電商,最高每日百萬訂單,處理訂單系統需要什麼樣的服務器配置?
這個問題比較業餘,因爲很多不同的服務器配置都能支撐(1.5G 16G 都有可能啊)
我們做一個假設吧,1小時360000個訂單。集中時間段, 100個訂單/秒,(找一小時內的高峯期,可能是1000訂單/秒)。我們就要找到這個最高峯的時間,保證你的架構能夠承接的住。
大多數情況下,是靠經驗值,然後做壓測。
如果非要計算的話,你預估一下,一個訂單對象產生需要多少內存?512K * 1000 = 500M內
專業一點的問法:要求響應時間在多少時間的情況下,比如100ms,我們去挑一個市面上性價比比較高的服務器,做壓測去測試,再不行加內存,再不行,就上雲服務器…
這樣說就OK了 -
案例2:12306遭遇春節大規模搶票應該如何支撐?(這個是架構上的一個設計,和調優關係不大)
12306應該是中國併發量最大的秒殺網站:號稱併發量最高100W
架構模型:CDN -> LVS -> NGINX -> 業務系統 -> 100臺機器,每臺機器1W併發(單機10K問題),目前這個問題已解決,主要是用redis
.業務流程:普通電商訂單 -> 下單 ->訂單系統(IO)減庫存 ->生成訂單,等待用戶付款
12306的一種可能的模型,是異步來進行的: 下單 -> 減庫存 和 訂單(redis kafka) 同時異步進行 ->等付款,付完款,持久化到Hbase, MySQL等等
.
減庫存最後還會把壓力壓到一臺服務器,怎麼辦?可以做分佈式本地庫存 + 單獨服務器做庫存均衡
大流量的處理方法:分而治之,每臺機器只減自己機器上有的庫存
流量傾斜的問題怎麼解決?比如有的機器上已經沒庫存了,有的機器上還剩很多?
這時候你還需要一臺單獨的服務器,去做所有服務器的平衡,如果某臺服務器沒庫存了,從別的機器上挪一些過去。 -
怎麼得到一個事務會消耗多少內存?
1、弄臺機器,看能承受多少TPS?是不是達到目標?擴容或調優,讓它達到
2、用壓測來確定
優化環境
- (這個可以稍微改一下寫進簡歷中)
有一個50萬PV的文檔資料類網站(從磁盤提取文檔到內存)原服務器32位,1.5G
的堆,用戶反饋網站比較緩慢。因此公司決定升級,新的服務器爲64位,16G的堆內存,結果用戶反饋卡頓十分嚴重,反而比以前效率更低了!- 爲什麼原網站慢?
因爲很多用戶瀏覽數據,很多用戶瀏覽導致很多數據Load到內存,產生了很多文檔對應的Java包裝對象(而不是文檔對象,文檔本身可以走Nginx)。內存不足,頻繁GC,STW長,響應時間變慢 - 爲什麼會更卡頓?
內存越大,FGC時間越長 - 咋辦?
PS 換成 PN + CMS,或者 G1
或者業務上的調整,文檔不走JVM
- 爲什麼原網站慢?
- 系統CPU經常100%,如何調優?(面試高頻)
這樣回答:推理過程是:CPU100%,那麼一定有線程在佔用系統資源,所以- 找出哪個進程cpu高(top命令)
- 該進程中的哪個線程cpu高(top -Hp)
- 如果是java程序,導出該線程的堆棧 (jstack)
- 查找哪個方法(棧幀)消耗時間,哪個方法調用的哪個方法 (jstack),然後去看這個方法的代碼
- 工作線程佔比高 | 垃圾回收線程佔比高
- 系統內存飆高,如何查找問題?(面試高頻)
- 導出堆內存 (jmap)
- 分析 (jhat jvisualvm mat jprofiler … )
- 如何監控JVM
- jstat jvisualvm jprofiler arthas top…