jvm調優的工具介紹

jvm調優實戰筆記之基礎知識簡介

I. 背景

java後端,提供了一個svg渲染的服務,在qps較大時,會出現頻繁的gc,而此時的服務器性能自己並無達到瓶頸(cpu,load,io都不過高)所以考慮調整一下jvm的相關參數,看是否能夠提高服務性能html

jvm相關參數記錄java

-XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBef
oreRemark -XX:+ExplicitGCInvokesConcurrent -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/xxx/java.hprof -XX:InitialCodeCacheSize=134217728 -XX:InitialHeapSize=4294967296 -XX:MaxDirectMemorySize=1073741824 -XX:MaxHeapSize=4294967296 -XX:MaxMetaspaceSize=268435456 -XX:MaxNewSize=2147483648 -XX:MetaspaceSize=268435456 -XX:NewSize=2147483648 -XX:OldPLABSize=16 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:ReservedCodeCacheSize=268435456 -XX:SurvivorRatio=10 -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

2. 監控工具

使用tsar做爲服務器性能監控工具,因此前提是先安裝tsarnginx

wget -O tsar.zip https://github.com/alibaba/tsar/archive/master.zip --no-check-certificate
unzip tsar.zip
cd tsar
make
make install

監控命令git

tsar --cpu --swap -i1 -l

說明github

tsar相關能夠參考: Linux系統性能監控工具介紹之-tsar算法

II. 相關知識點簡介

截取幾條gc日誌apache

2018-01-02T10:49:20.390+0800: 9.015: [GC (Allocation Failure) 2018-01-02T10:49:20.390+0800: 9.015: [ParNew: 1922431K->134118K(1922432K), 0.1486593 secs] 1934749K->201350K(4019584K), 0.1487460 secs] [Times: user=0.33 sys=0.05, real=0.14 secs]
2018-01-02T10:49:25.374+0800: 13.999: [GC (Allocation Failure) 2018-01-02T10:49:25.374+0800: 13.999: [ParNew: 1881830K->93708K(1922432K), 0.0910714 secs] 1949062K->197949K(4019584K), 0.0911833 secs] [Times: user=0.26 sys=0.01, real=0.09 secs]
2018-01-02T10:55:53.013+0800: 401.639: [GC (GCLocker Initiated GC) 2018-01-02T10:55:53.013+0800: 401.639: [ParNew: 1841429K->142552K(1922432K), 0.0629031 secs] 1945670K->246793K(4019584K), 0.0630512 secs] [Times: user=0.14 sys=0.01, real=0.06 secs]
2018-01-02T10:55:55.076+0800: 403.701: [GC (GCLocker Initiated GC) 2018-01-02T10:55:55.076+0800: 403.701: [ParNew: 1890281K->59983K(1922432K), 0.0661778 secs] 1994522K->201875K(4019584K), 0.0663176 secs] [Times: user=0.15 sys=0.01, real=0.07 secs]
2018-01-02T11:47:25.271+0800: 3493.897: [GC (Allocation Failure) 2018-01-02T11:47:25.271+0800: 3493.897: [ParNew: 1807695K->20975K(1922432K), 0.0193077 secs] 1949587K->162867K(4019584K), 0.0195351 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]
2018-01-02T11:56:50.621+0800: 4059.247: [GC (GCLocker Initiated GC) 2018-01-02T11:56:50.622+0800: 4059.247: [ParNew: 1774543K->108899K(1922432K), 0.0401606 secs] 1916434K->250791K(4019584K), 0.0403586 secs] [Times: user=0.10 sys=0.00, real=0.04 secs]

1. CMS GC日誌格式分析

截取上面日誌中的第一條,分別說明每一項是什麼意思後端

2018-01-02T10:49:20.390+0800: 9.015: [GC (Allocation Failure) 2018-01-02T10:49:20.390+0800: 9.015: [ParNew: 1922431K->134118K(1922432K), 0.1486593 secs] 1934749K->201350K(4019584K), 0.1487460 secs] [Times: user=0.33 sys=0.05, real=0.14 secs]數組

  • 2018-01-02T10:49:20.390+0800 :發生gc的時間
  • 9.015 - GC開始,相對JVM啓動的相對時間,單位是秒
  • GC - 區別FullGC和MinorGC的標識,此處表示爲MinorGC
  • (Allocation Failure) - 發生gc的緣由,此處表示空間不足,致使分配失敗
  • ParNew – 收集器的名稱,它預示了年輕代使用一個並行的 mark-copy stop-the-world 垃圾收集器
  • 1922431K->134118K – 收集先後年輕代的使用狀況,未回收以前,大小爲1922431K, 回收完畢以後,大小爲134118K, 因此回收大小爲: 1922431K - 134118K
  • (1922432K) - 整個年輕代的容量
  • 0.1486593 secs - 這個解釋用原滋原味的解釋:Duration for the collection w/o final cleanup.
  • 1934749K->201350K - 收集先後整個堆的使用狀況
  • (4019584K) - 整個堆的容量
  • 0.1487460 secs – ParNew收集器標記和複製年輕代活着的對象所花費的時間(包括和老年代通訊的開銷、對象晉升到老年代時間、垃圾收集週期結束一些最後的清理對象等的花銷);
  • [Times: user=0.78 sys=0.01, real=0.11 secs] – GC事件在不一樣維度的耗時,具體的用英文解釋起來更加合理:
    • user – Total CPU time that was consumed by Garbage Collector threads during this collection
    • sys – Time spent in OS calls or waiting for system event
    • real – Clock time for which your application was stopped. With Parallel GC this number should be close to (user time + system time) divided by the number of threads used by the Garbage Collector. In this particular case 8 threads were used. Note that due to some activities not being parallelizable, it always exceeds the ratio by a certain amount.

2. CMS簡介

後端服務選用的就是CMS,那麼就有必要看一下這個CMS究竟是個什麼東西安全

CMS

Concurrent Mark Sweep 收集器,是一種以獲取最短回收停頓時間爲目標的收集器,核心就是標籤-清除算法

步驟劃分

  • 初始標記 (CMS initial mark) : 標記GC Roots能直接關聯到的對象,速度很快,會暫停
  • 併發標記 (CMS concurrent mark) : 進行 GC Roots Tracing的過程
  • 從新標記 (CMS remark) : 爲了修正併發標記期間,由於程序繼續運做致使標記變更的那一部分對象的標記記錄,通常會長於初始標記時間,遠小於併發標記的時間
  • 併發清除 (CMS concurrent sweep) :

說明,初始標記和從新標記的時候,會暫停服務;後面兩個則是併發修改

標記清除算法

一句話描述:

標記全部須要回收的對象,在標記完成後,統一回收全部被標記的對象

常見的兩個問題: 效率不高;回收後大量的碎片

3. 內存分配和回收策略

a. 對象優先在Eden分配

大多數場景下,對象在新生代Eden區分配,當Eden去沒有足夠的空間進行分配時,虛擬機發起一次 Minor GC

  • 新生代MinorGC : 發生在新生代的垃圾收集動做,由於java對象大多都具有朝生夕滅的特性是,因此通常MinorGC很是頻繁,通常回收速度也很快
  • 老年代MajorGC(FullGC) : 發生在老年代的GC,一般就伴隨至少一次的MinorGC(非絕對),通常較慢,是MinorGC的十倍以上

b. 大對象直接進入老年代

須要大量連續內存空間的Java對象,一般是數組,同構 -XX:PretenuresizeThreshold 參數,來設置大對象的閥值,超過這個閥值的直接分配在年老代,避免在Eden區及兩個Survivor區指尖發生大量的內存複製

c. 長期存活的對象將進入老年代

既然虛擬機採用分代收集的思想來管理內存,在回收時,就必須能識別哪些對象應放在新生代,那些對象應放在老年代中

每一個對象都有個Age的計數器,對象在Eden出生並通過第一次MinorGC後仍存在,且能夠被Survivor容納的話,會被移動到Survivor空間中,並設置Age爲1

對象在Survivor區沒多通過一次MinorGC,則age+1

當age超過閥值(默認15),就會晉升到老年代

閥值能夠經過 -XX:MaxTenuringThreshold來設置

d. 動態對象年齡斷定

若是在Survivor空間中相同年齡全部對象的大小的總和,大於Survivor空間的一半,則年齡大於或等於該年齡的對象就能夠進入老年代,無序等Age達到閥值

e. 空間分配擔保

在發生MinorGC以前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代全部對象總空間,若是成立,則Minor GC能夠確保老是安全的;

不然,查看 HandlePromotionFailure參數,是否容許擔保失敗

若容許,則繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,若大於,則嘗試MinorGC

不然進行FullGC

3. jstat 命令簡介

既然問題是頻繁的gc引發的,那麼觀察新生代,老年代對象佔用空間的狀況就不可避免了,因此jstat命令不得不出現了

截一個線程圖

$ jstat -gcutil 11573 1000 5
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00  34.39  24.68  68.01  98.12  96.30   3051  170.096   242   18.429  188.525
  0.00  34.39  26.29  68.01  98.12  96.30   3051  170.096   242   18.429  188.525
  0.00  34.39  27.45  68.01  98.12  96.30   3051  170.096   242   18.429  188.525
  0.00  34.39  28.32  68.01  98.12  96.30   3051  170.096   242   18.429  188.525
  0.00  34.39  29.93  68.01  98.12  96.30   3051  170.096   242   18.429  188.525

a. 參數說明

  • -gcutil : 監視Java對情況,包括Eden區、兩個survivor區,老年代,永久代等,已用空間,gc時間等
  • 11573: java進程號
  • 1000: 每1s刷新一次
  • 5: 一共查詢5次

b. 輸出說明

  • S0, S1: 表示兩個 survivor區
  • E(Eden) : 新生代Eden
  • O(Old) : 老年代Old
  • M(metaspace) : 元空間,本地內存, 在1.8移除了永久代改爲這個
  • YGC : 程序運行以來,發生Minor GC(Young GC)次數
  • YGCT : Minor GC 總耗時(單位s)
  • FGC : Full GC的總次數
  • FGCT : Full GC的總耗時 (單位s)
  • GCT : 全部GC的總耗時 (單位s)

III. 監控測試

0. 準備

a. 首先是獲取對應的進程號

jps -l
jinfo xxx

抓圖

$ jps -l
30916 sun.tools.jps.Jps
2909 org.apache.catalina.startup.Bootstrap

b. 服務器性能監控命令

## 主要查看cpu和nginx訪問的監控
tsar --cpu --nginx -i1 -l

抓圖:

Time              -----------------------cpu---------------------- ----------------------------------nginx---------------------------------
Time                user     sys    wait    hirq    sirq    util   accept  handle    reqs  active    read   write    wait     qps      rt
03/01/18-11:29:37  16.54    1.50    0.00    0.00    0.00   18.05     2.00    2.00    6.00   15.00    0.00    1.00   14.00    6.00   89.50
03/01/18-11:29:38  26.07    1.75    0.00    0.00    0.00   27.82     3.00    3.00   10.00   15.00    0.00    1.00   14.00   10.00   47.10
03/01/18-11:29:39  19.60    1.01    0.00    0.00    0.00   20.60     4.00    4.00   11.00   15.00    0.00    1.00   14.00   11.00   37.82
03/01/18-11:29:40  28.75    2.50    0.00    0.00    0.25   31.50     2.00    2.00   10.00   15.00    0.00    1.00   14.00   10.00   79.30
03/01/18-11:29:41  14.07    1.51    0.00    0.00    0.00   15.58     1.00    1.00   10.00   15.00    0.00    3.00   12.00   10.00   51.30
03/01/18-11:29:42  20.60    1.01    0.00    0.00    0.00   21.61     6.00    6.00   13.00   15.00    0.00    1.00   14.00   13.00   44.69

c. jvm內存的監控

jstat -gcutil 4354 1000

抓圖:

$ jstat -gcutil 2909 1000
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 29.03   0.00  66.34  16.34  98.57  96.32    200    6.393     0    0.000    6.393
 29.03   0.00  66.37  16.34  98.57  96.32    200    6.393     0    0.000    6.393
 29.03   0.00  66.50  16.34  98.57  96.32    200    6.393     0    0.000    6.393
 29.03   0.00  66.54  16.34  98.57  96.32    200    6.393     0    0.000    6.393

d. 查看內存中對象的個數和大小

jmap -histo 4354

抓圖

num     #instances         #bytes  class name
----------------------------------------------
   1:         78179      181546608  [I
   2:          1259      175880312  [S
   3:         35915       65527520  [B
   4:        242125       40558408  [C
   5:        571604       13718496  java.util.concurrent.atomic.AtomicLong
   6:        233282        5598768  java.lang.String
   7:         55177        5296992  java.util.jar.JarFile$JarFileEntry
   8:        119906        3836992  java.util.HashMap$Node
   9:         33327        2932776  java.lang.reflect.Method
  10:          1147        2303216  [Ljava.util.concurrent.atomic.AtomicLong;

e. 壓測模擬工具

Jmetter

  • 添加線程組
    • 新增http請求
    • 添加監聽器中,結果的監控:圖形結果,聚合報告,查看結果樹,用表格查看結果
  • http請求中配置參數
    • 協議
    • 域名or IP + 端口號
    • 編碼: utf-8
    • 請求方法 + 請求路徑
    • 請求參數,支持文件上傳,注意編碼方式

15AFB591-DB24-4525-9EE8-ECA190A5BF14.png

IV. 參考

V. 其餘

聲明

盡信書則不如,已上內容,純屬一家之言,因本人能力通常,看法不全,若有問題,歡迎批評指正

掃描關注,java分享

QrCode

相關文章
相關標籤/搜索