Tomcat容器是運行在JVM上的, 其默認內存通常都很小(物理內存的1/64), 在實際生產環境中, 若不配置則會極大浪費服務器資源, 影像系統的性能. 能夠經過調整JVM啓動參數, 使得Tomcat擁有更好的性能.tomcat
對於JVM的優化主要有兩個方面: 內存調優 和 垃圾收集策略調優.服務器
Tomcat 的運行內存 = Xmx(初始內存大小) + Perm Generation(JDK 7中的永久代大小) + Java應用建立的線程數 * 1MB.併發
Java 應用每建立一個線程, JVM 進程的內存中就會建立一個 Thread 對象, 同時也會在操做系統中建立一個真正的物理線程(參考JVM規範), 操做系統會在 Tomcat 的空閒內存中建立這個物理線程, 而不是在 JVM 的 Xmx 堆內存中建立.工具
在 JDK 1.4中, 默認的棧大小是256KB/線程, 但自 JDK 5(爲了推廣的方便, JDK 後續版本再也不是1.x命名)開始, 默認的棧大小變爲1M/線程. 舉例: 若是系統剩餘內存爲400M, 則Java應用最多能建立400個可用線程.性能
結論: 要想建立更多的線程, 必須減小分配給JVM的最大內存. 優化
-server # JVM的server模式, 在多CPU服務器中性能能夠獲得更好地發揮. 默認爲client. 配置server模式時要將其做爲第一個參數. -Xmx4g # Java Heap的最大可用內存, 默認爲物理內存的1/4(已在JDK 7下驗證, 最大值爲30638MB, 總內存126GB的23.75%). # 在只運行Tomcar容器的服務器中, 建議設置爲物理內存的50%~80%. -Xms4g # Java Heap的初始大小, 默認值爲物理內存的1/64(已在JDK 7下驗證, 內存126GB, 初始值爲2GB). -Xss128k # 每一個線程的Stack大小. 在相同物理內存下, 減少這個值能生成更多的線程, # 可是操做系統對一個進程內的線程數是有限制的, 經驗範圍是3000~5000. -XX:NewRatio=4 # 設置新生代(包括Eden和兩個Survivor區)與老年代的比值(除去持久代), 默認爲2, 即新生代與老年代所佔比值爲1:2, 新生代佔整個堆棧的1/3. -XX:SurvivorRatio=4 # 設置新生代中Eden區與1個Survivor區的大小比值. 默認爲8, 即Eden區佔新生代的80%, 2個Survivor分別佔新生代的10%. # 設置爲4, 則兩個Survivor區與一個Eden區的比值爲2:4, 一個Survivor區佔整個新生代的1/6. -Xmn1024m # 設置Young Generation所佔用的Java Heap大小爲1g. 此值對系統性能影響較大, Sun官方推薦配置爲整個堆的3/8(或Xmx的1/4~1/3左右). # 也可以使用-XX:NewSize和-XX:MaxNewsize設置新生代的初始值和最大值. # 注意: -Xmn 與 -XX:NewSize、-XX:MaxNewSize 的優先級: -XX:NewRatio的值會被忽略. # 1. 高優先級: -XX:NewSize/-XX:MaxNewSize # 2. 中優先級: -Xmn, 等效於同時設置 -Xmn = -XX:NewSize = -XX:MaxNewSize 三者的值 # 3. 低優先級: -XX:NewRatio # -Xmn參數是在JDK 1.4 開始支持, 推薦使用之. -XX:NewSize=1g # 設置新生代的大小, 默認爲1.25MB(已在JDK 7下驗證). 若顯示設置此值, 將使得NewRatio選項失效. -XX:OldSize=2g # 設置老年代的大小, 默認爲5.1875MB(已在JDK 7下驗證). -XX:PermSize=128m # JDK 7及如下版本適用: 設置Java Heap中永久代的初始大小, 默認爲20.75MB(已在JDK 7下驗證, client、server模式下均相同). -XX:MaxPermSize=256m # JDK 7及如下版本適用: 設置Java Heap中永久代的最大值. 默認爲82.0MB(已在JDK 7下驗證, client、server模式下均相同). -XX:MetaspaceSize=128m # JDK 8及以上版本適用: 初始元空間的大小, 默認爲21MB(實際爲20.79MB左右, 已驗證). -XX:MaxMetaspaceSize=256m # JDK 8及以上版本適用: 最大元空間的大小. 默認無上限(在126GB物理內存的服務器中, 默認值爲(2^44-1)MB, 已驗證).
總結:spa
- 情形一: 若是不指定Xmx、Xms和NewSize、OldSize, 則系統將基於Xms=1/64總內存大小, 對各個Space按照NewRatio=2進行空間的分配, 此時NewSize與OldSize的默認大小將失效.
- 情形二: 若是指定了Xmx、Xms, 未指定NewSize、OldSize, 則系統將優先知足 NewRatio=2, 且OldSize+NewSize=Xms, 此時NewSize與OldSize的默認大小將失效.
- 結論: 除非顯式指定NewSize與OldSize的值, 不然它們的默認配置通常都不會獲得知足. 顯式指定其中任一個, 另外一個就會基於默認值, 並根據應用程序的消耗動態分配空間大小.
JVM內存方面的調優, 須要在 ${TOMCAT_HOME}/bin/catalina.sh
文件中調整, 配置 JAVA_OPTS 變量便可. 在啓動Tomcat時, 會執行catalina.sh中的腳本, 將 JAVA_OPTS 做爲JVM的啓動參數進行處理.操作系統
具體可參考以下配置(示例服務器配置: 126g的物理內存, 2個10核心20線程的物理CPU):.net
# 在文件最前面(即cygwin=false以前)設置, $JAVA_OPTS 的做用是保留原有的設置, 防止這次修改覆蓋以前的設置 JAVA_OPTS="$JAVA_OPTS -Xmx96g -Xms96g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
說明:
- 若不指定Xmx, 即Java Heap的最大值, 程序啓動時, JVM會調整其大小以知足程序運行的須要. 每次調整時, 都會對堆進行一次徹底垃圾收集(即Full GC), 比較影響性能. 所以推薦明確指定Xmx的大小.
- 令
Xmx=Xms
會有更好地性能表現: 能避免JVM在每次垃圾收集後從新動態調節堆空間, 由於頻繁伸縮堆大小將帶來額外的性能消耗.- JVM有2中模式: client客戶端模式 和 server服務端模式 , 平時開發中使用的可能是默認的client模式. 可經過命令行參數
-server
強制開啓server模式. 二者之間的最大區別是, JVM對server模式作了大量優化: 雖然server模式下應用程序啓動較慢, 但在長時間運行下, 程序運行效率會明顯高於client模式, 即 client模式不適合須要長時間運行的項目 .
元空間的調優:
元空間的大小將受限於機器的內存的限制. 限制類的元數據的內存大小, 以免出現虛擬內存切換以及本地內存分配失敗.
若是可能出現類加載器泄漏, 應當配置此參數指定大小. 32位機器上, 若是地址空間可能會被耗盡, 也應當配置此參數.
元空間的初始大小是21M——這是GC的初始高水位線, 超過這個大小會進行Full GC來進行類的收集.
若是啓動後GC過於頻繁, 請將該值設置得大一些, 以便推遲GC的執行時間.
# 因爲配置了環境變量, 在任意目錄下使用jps及jmap命令, 便可調用相關工具: # 使用 jps 查看 Java 的全部進程 [root@localhost ~]# jps 14308 Bootstrap 15620 Jps # 其中 Bootstrap 進程就是 Tomcat, 其進程號爲14308. # 經過 jmap 工具查看其內存相關配置 [root@localhost ~]# jmap -heap 14308 # 顯示如下結果 Attaching to process ID 24980, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.151-b12 using thread-local object allocation. Parallel GC with 28 thread(s) # 默認使用併發GC策略 Heap Configuration: # 堆的配置參數 MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 103079215104 (98304.0MB) # 最大堆內存 NewSize = 34359738368 (32768.0MB) # 新生代大小, 因爲默認的NewRatio=2, 因此是1/3的堆大小 MaxNewSize = 34359738368 (32768.0MB) OldSize = 68719476736 (65536.0MB) # 老年代大小, 因爲默認的NewRatio=2, 因此是2/3的堆大小 NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) # 元空間大小 CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB # 最大元空間大小 G1HeapRegionSize = 0 (0.0MB) Heap Usage: # 堆的使用狀況 PS Young Generation Eden Space: # 新生代的伊甸區, 因爲默認的SurvivorRatio=8, 因此是6/8的NewSize capacity = 25769803776 (24576.0MB) used = 9742123824 (9290.813278198242MB) free = 16027679952 (15285.186721801758MB) 37.80441600829363% used From Space: # 新生代的From區, 因爲默認的SurvivorRatio=8, 因此是1/8的NewSize capacity = 4294967296 (4096.0MB) used = 0 (0.0MB) free = 4294967296 (4096.0MB) 0.0% used To Space: # 新生代的To區, 因爲默認的SurvivorRatio=8, 因此是1/8的NewSize capacity = 4294967296 (4096.0MB) used = 0 (0.0MB) free = 4294967296 (4096.0MB) 0.0% used PS Old Generation # 老年代, 因爲默認的NewRatio=2, 因此是2/3的堆大小 capacity = 68719476736 (65536.0MB) used = 254298704 (242.5181427001953MB) free = 68465178032 (65293.481857299805MB) 0.37005331832915545% used 23928 interned Strings occupying 3198312 bytes.
Tomcat的GC策略通常都是與其內存參數一塊兒配置的, 與應用複雜度相匹配的GC策略、與服務器性能相適應的內存比例, 都將使得系統性能獲得大幅提高.
GC策略方面的調優, 也是在 ${TOMCAT_HOME}/bin/catalina.sh
文件中調整 -- 一樣是配置 JAVA_OPTS 變量便可.
以JDK 八、Tomcat 8爲例, 服務器內存爲126GB, 做出以下配置:
經過Solr集羣大批量導入數據的應用中, Parallel GC策略的暫停時間太長, 因此選擇CMS收集器.
# 下述配置各自獨佔一行, 要置於"cygwin=false"以前. # 配置內存 JAVA_OPTS="-server -Xmx96g -Xms96g -Xmn35g -XX:OldSize=55g -Xss128k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m" # 配置GC策略 JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15 -XX:CMSInitiatingOccupancyFraction=40 -XX:CMSFullGCsBeforeCompaction=0 -XX:+ExplicitGCInvokesConcurrent -XX:SoftRefLRUPolicyMSPerMB=0 -XX:MaxGCPauseMillis=100 -Xnoclassgc "
其中Java Heap的初始大小和最大大小均設置爲96g, 76%的物理內存(以不超過80%爲宜).
參考資料:
版權聲明
做者: 馬瘦風
出處: 博客園 馬瘦風的博客
您的支持是對博主的極大鼓勵, 感謝您的閱讀.
本文版權歸博主全部, 歡迎轉載, 但未經博主贊成必須保留此段聲明, 且在文章頁面明顯位置給出原文連接, 不然博主保留追究法律責任的權利.