1. 程式人生 > >JVM gc引數設定與分析

JVM gc引數設定與分析

原文:

概述

java的最大好處是自動垃圾回收,這樣就無需我們手動的釋放物件空間了,但是也產生了相應的負效果,gc是需要時間和資源的,不好的gc會嚴重影響系統的系能,因此良好的gc是JVM的高效能的保證。JVM堆分為新生代,舊生代和年老代,新生代可用的gc方式有:序列gc(Serial Copying),並行回收gc(Parellel Scavenge),並行gc(ParNew),舊生代和年老代可用的gc方式有序列gc(Serial MSC),並行gc(Parallel MSC),併發gc(CMS)。

回收方式的選擇

jvm有client和server兩種模式,這兩種模式的gc預設方式是不同的:

client模式下,新生代選擇的是序列gc,舊生代選擇的是序列gc

server模式下,新生代選擇的是並行回收gc,舊生代選擇的是並行gc

一般來說我們系統應用選擇有兩種方式:吞吐量優先和暫停時間優先,對於吞吐量優先的採用server預設的並行gc方式,對於暫停時間優先的選用併發gc(CMS)方式。

CMS gc

CMS,全稱Concurrent Low Pause Collector,是jdk1.4後期版本開始引入的新gc演算法,在jdk5和jdk6中得到了進一步改進,它的主要適合場景是對響應時間的重要性需求大於對吞吐量的要求,能夠承受垃圾回收執行緒和應用執行緒共享處理器資源,並且應用中存在比較多的長生命週期的物件的應用。CMS是用於對tenured generation的回收,也就是年老代的回收,目標是儘量減少應用的暫停時間,減少full gc發生的機率,利用和應用程式執行緒併發的垃圾回收執行緒來標記清除年老代。在我們的應用中,因為有快取的存在,並且對於響應時間也有比較高的要求,因此希望能嘗試使用CMS來替代預設的server型JVM使用的並行收集器,以便獲得更短的垃圾回收的暫停時間,提高程式的響應性。

CMS並非沒有暫停,而是用兩次短暫停來替代序列標記整理演算法的長暫停,它的收集週期是這樣:

初始標記(CMS-initial-mark) -> 併發標記(CMS-concurrent-mark) -> 重新標記(CMS-remark) -> 併發清除(CMS-concurrent-sweep) ->併發重設狀態等待下次CMS的觸發(CMS-concurrent-reset)。

其中的1,3兩個步驟需要暫停所有的應用程式執行緒的。第一次暫停從root物件開始標記存活的物件,這個階段稱為初始標記;第二次暫停是在併發標記之後,暫停所有應用程式執行緒,重新標記併發標記階段遺漏的物件(在併發標記階段結束後物件狀態的更新導致)。第一次暫停會比較短,第二次暫停通常會比較長,並且 remark這個階段可以並行標記。

而併發標記、併發清除、併發重設階段的所謂併發,是指一個或者多個垃圾回收執行緒和應用程式執行緒併發地執行,垃圾回收執行緒不會暫停應用程式的執行,如果你有多於一個處理器,那麼併發收集執行緒將與應用執行緒在不同的處理器上執行,顯然,這樣的開銷就是會降低應用的吞吐量。Remark階段的並行,是指暫停了所有應用程式後,啟動一定數目的垃圾回收程序進行並行標記,此時的應用執行緒是暫停的。

full gc

full gc是對新生代,舊生代,以及持久代的統一回收,由於是對整個空間的回收,因此比較慢,系統中應當儘量減少full gc的次數。

如下幾種情況下會發生full gc:

  1. 舊生代空間不足
  2. 持久代空間不足
  3. CMS GC時出現了promotion failed和concurrent mode failure
  4. 統計得到新生代minor gc時晉升到舊生代的平均大小小於舊生代剩餘空間
  5. 直接呼叫System.gc,可以DisableExplicitGC來禁止
  6. 存在rmi呼叫時,預設會每分鐘執行一次System.gc,可以通過-Dsun.rmi.dgc.server.gcInterval=3600000來設定大點的間隔。

Gc日誌引數

通過在tomcat啟動指令碼中新增相關引數生成gc日誌

  • -verbose.gc開關可顯示GC的操作內容。開啟它,可以顯示最忙和最空閒收集行為發生的時間、收集前後的記憶體大小、收集需要的時間等。
  • 開啟-xx:+printGCdetails開關,可以詳細瞭解GC中的變化。
  • 開啟-XX:+PrintGCTimeStamps開關,可以瞭解這些垃圾收集發生的時間,自JVM啟動以後以秒計量。
  • 最後,通過-xx:+PrintHeapAtGC開關了解堆的更詳細的資訊。
  • 為了瞭解新域的情況,可以通過-XX:+PrintTenuringDistribution開關了解獲得使用期的物件權。
  • -Xloggc:$CATALINA_BASE/logs/gc.log gc日誌產生的路徑
  • -XX:+PrintGCApplicationStoppedTime 輸出GC造成應用暫停的時間
  • -XX:+PrintGCDateStamps GC發生的時間資訊

Opentsdb開啟Gc引數

1 2 3 4 5 6 7 8 9 10 11 12 # tsdb.local GCARGS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps\ -XX:+PrintTenuringDistribution -Xloggc:/tmp/tsd-gc-`date +%s`.log" if test -t 0; then # if stdin is a tty, don't turn on GC logging. GCARGS= fi # The Sun JDK caches all name resolution results forever, which is stupid. # This forces you to restart your application if any of the backends change # IP. Instead tell it to cache names for only 10 minutes at most. FIX_DNS='-Dsun.net.inetaddr.ttl=600' JVMARGS="$JVMARGS $GCARGS $FIX_DNS"

常用JVM引數

分析gc日誌後,經常需要調整jvm記憶體相關引數,常用引數如下

  • -Xms:初始堆大小,預設為實體記憶體的1/64(<1GB);預設(MinHeapFreeRatio引數可以調整)空餘堆記憶體小於40%時,JVM就會增大堆直到-Xmx的最大限制
  • -Xmx:最大堆大小,預設(MaxHeapFreeRatio引數可以調整)空餘堆記憶體大於70%時,JVM會減少堆直到 -Xms的最小限制
  • -Xmn:新生代的記憶體空間大小,注意:此處的大小是(eden+ 2 survivor space)。與jmap -heap中顯示的New gen是不同的。整個堆大小=新生代大小 + 老生代大小 + 永久代大小。在保證堆大小不變的情況下,增大新生代後,將會減小老生代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
  • -XX:SurvivorRatio:新生代中Eden區域與Survivor區域的容量比值,預設值為8。兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區佔整個年輕代的1/10。
  • -Xss:每個執行緒的堆疊大小。JDK5.0以後每個執行緒堆疊大小為1M,以前每個執行緒堆疊大小為256K。應根據應用的執行緒所需記憶體大小進行適當調整。在相同實體記憶體下,減小這個值能生成更多的執行緒。但是作業系統對一個程序內的執行緒數還是有限制的,不能無限生成,經驗值在3000~5000左右。一般小的應用, 如果棧不是很深, 應該是128k夠用的,大的應用建議使用256k。這個選項對效能影響比較大,需要嚴格的測試。和threadstacksize選項解釋很類似,官方文件似乎沒有解釋,在論壇中有這樣一句話:"-Xss is translated in a VM flag named ThreadStackSize”一般設定這個值就可以了。
  • -XX:PermSize:設定永久代(perm gen)初始值。預設值為實體記憶體的1/64。
  • -XX:MaxPermSize:設定持久代最大值。實體記憶體的1/4。

示例

下面對如下的引數進行分析:

JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4
-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log 
-Djava.awt.headless=true 
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails 
-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000
-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"
  • -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m

Xms,即為jvm啟動時得JVM初始堆大小,Xmx為jvm的最大堆大小,xmn為新生代的大小,permsize為永久代的初始大小,MaxPermSize為永久代的最大空間。

  • -XX:SurvivorRatio=4

SurvivorRatio為新生代空間中的Eden區和救助空間Survivor區的大小比值,預設是32,也就是說Eden區是 Survivor區的32倍大小,要注意Survivo是有兩個區的,因此Surivivor其實佔整個young genertation的1/34。調小這個引數將增大survivor區,讓物件儘量在survitor區呆長一點,減少進入年老代的物件。去掉救助空間的想法是讓大部分不能馬上回收的資料儘快進入年老代,加快年老代的回收頻率,減少年老代暴漲的可能性,這個是通過將-XX:SurvivorRatio 設定成比較大的值(比如65536)來做到。

  • -verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log

將虛擬機器每次垃圾回收的資訊寫到日誌檔案中,檔名由file指定,檔案格式是平檔案,內容和-verbose:gc輸出內容相同。

  • -Djava.awt.headless=true

Headless模式是系統的一種配置模式。在該模式下,系統缺少了顯示裝置、鍵盤或滑鼠。

  • -XX:+PrintGCTimeStamps -XX:+PrintGCDetails

設定gc日誌的格式

  • -Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000

指定rmi呼叫時gc的時間間隔

  • -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15

採用併發gc方式,經過15次minor gc 後進入年老代

  • Xms 是指設定程式啟動時佔用記憶體大小。一般來講,大點,程式會啟動的快一點,但是也可能會導致機器暫時間變慢。
    
    Xmx 是指設定程式執行期間最大可佔用的記憶體大小。如果程式執行需要佔用更多的記憶體,超出了這個設定值,就會丟擲OutOfMemory異常。
    
    Xss 是指設定每個執行緒的堆疊大小。這個就要依據你的程式,看一個執行緒大約需要佔用多少記憶體,可能會有多少執行緒同時執行等。
    
    以上三個引數的設定都是預設以Byte為單位的,也可以在數字後面新增[k/K]或者[m/M]來表示KB或者MB。而且,超過機器本身的記憶體大小也是不可以的,否則就等著機器變慢而不是程式變慢了。
    
    -Xmsn
    Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
    Examples:
           -Xms6291456
           -Xms6144k
           -Xms6m
          
    -Xmxn
    Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
    Examples:
           -Xmx83886080
           -Xmx81920k
           -Xmx80m
    
    -Xssn
    Set thread stack size. 
    

一些常見問題

  • 為了避免Perm區滿引起的full gc,建議開啟CMS回收Perm區選項:
    +CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
    
  • 預設CMS是在tenured generation沾滿68%的時候開始進行CMS收集,如果你的年老代增長不是那麼快,並且希望降低CMS次數的話,可以適當調高此值:
    -XX:CMSInitiatingOccupancyFraction=80
    
  • 遇到兩種fail引起full gc:Prommotion failed和Concurrent mode failed時:

Prommotion failed的日誌輸出大概是這樣:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K( 166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]

這個問題的產生是由於救助空間不夠,從而向年老代轉移物件,年老代沒有足夠的空間來容納這些物件,導致一次full gc的產生。解決這個問題的辦法有兩種完全相反的傾向:增大救助空間、增大年老代或者去掉救助空間。

Concurrent mode failed的日誌大概是這樣的:

(concurrent mode failure): 1228795K->1228598K(1228800K), 7.6748280 secs] 1911483K->1681165K(1911488K), [CMS Perm : 225407K->225394K(262144K)], 7.6751800 secs]

問題的產生原因是由於CMS回收年老代的速度太慢,導致年老代在CMS完成前就被沾滿,引起full gc,避免這個現象的產生就是調小-XX:CMSInitiatingOccupancyFraction引數的值,讓CMS更早更頻繁的觸發,降低年老代被沾滿的可能。

Gc日誌分析工具

GCHisto

直接點選gchisto.jar就可以執行,點add載入gc.log

統計了總共gc次數,youngGC次數,FullGC次數,次數的百分比,GC消耗的時間,百分比,平均消耗時間,消耗時間最小最大值等

  • 統計的圖形化表示

  • YoungGC,FullGC不同消耗時間上次數的分佈圖,勾選可以顯示youngGC或fullGC單獨的分佈情況

  • 整個時間過程詳細的gc情況,可以對整個過程進行剖析

GCLogViewer

點選run.bat執行

整個過程gc情況的趨勢圖,還顯示了gc型別,吞吐量,平均gc頻率,記憶體變化趨勢等

Tools裡還能比較不同gc日誌:

HPjmeter

工具很強大,但只能開啟由以下引數生成的GC log, -verbose:gc -Xloggc:gc.log,新增其他引數生成的gc.log無法開啟。

GCViewer

這個工具用的挺多的,但只能在JDK1.5以下的版本中執行,1.6以後沒有對應。

garbagecat

其它監控方法

  • Jvisualvm

Jvisualvm動態分析jvm記憶體情況和gc情況,外掛:visualGC

jvisualvm還可以heapdump出對應hprof檔案(預設存放路徑:監控的伺服器 /tmp下),利用相關工具,比如HPjmeter可以對其進行分析

grep Full gc.log粗略觀察FullGC發生頻率

jstat –gcutil [pid] [intervel] [count]
  • jmap

jmap -histo pid可以觀測物件的個數和佔用空間

jmap -heap pid可以觀測jvm配置引數,堆記憶體各區使用情況

  • jprofiler,jmap dump出來用MAT分析

如果要分析的dump檔案很大的話,就需要很多記憶體,很容易crash。

所以在啟動時,我們應該加上一些引數: Java –Xms512M –Xmx1024M –Xss8M

參考資料:

相關推薦

JVM gc引數設定分析

原文: 概述 java的最大好處是自動垃圾回收,這樣就無需我們手動的釋放物件空間了,但是也產生了相應的負效果,gc是需要時間和資源的,不好的gc會嚴重影響系統的系能,因此良好的gc是JVM的高效能的保證。JVM堆分為新生代,舊生代和年老代,新生代可用的gc方式有:序列

JVM調優手冊之六:JVM引數設定分析

不管是YGC還是Full GC,GC過程中都會對導致程式執行中中斷,正確的選擇不同的GC策略,調整JVM、GC的引數,可以極大的減少由於GC工作,而導致的程式執行中斷方面的問題,進而適當的提高Java程式的工作效率。但是調整GC是以個極為複雜的過程,由於各個程式

JVM引數設定分析

不管是YGC還是Full GC,GC過程中都會對導致程式執行中中斷,正確的選擇不同的GC策略,調整JVM、GC的引數,可以極大的減少由於GC工作,而導致的程式執行中斷方面的問題,進而適當的提高Java程式的工作效率。但是調整GC是以個極為複雜的過程,由於各個程式

JVM系列:JVM引數設定分析

不管是YGC還是Full GC,GC過程中都會對導致程式執行中中斷,正確的選擇不同的GC策略,調整JVM、GC的引數,可以極大的減少由於GC工作,而導致的程式執行中斷方面的問題,進而適當的提高Java程式的工作效率。但是調整GC是以個極為複雜的過程,由於各個程式具備不同的特點

JVM 基本引數使用調優及JVM分析工具初探

一、JVM引數型別jvm引數型別一般包含以下三種類型:標準引數、X引數和XX引數。1.1引數型別說明1.1.1標準引數功能和輸出已經穩定得,在未來的JVM版本中不會修改的引數。圖1.jvm標準引數列表1.1.2 X引數非標準化引數 在未來的版本可能會改變 所有的引數都用-X開

JVM探祕:GC日誌收集分析

本系列筆記主要基於《深入理解Java虛擬機器:JVM高階特性與最佳實踐 第2版》,是這本書的讀書筆記。 收集GC日誌 不同的垃圾收集器,輸出的日誌格式各不相同,但也有一些相同的特徵。熟悉各個常用垃圾收集器的GC日誌,是進行JVM調優的必備一步。 解析GC日誌,首先需要收集日誌,常用的有以下JVM引數用來列

MySQL wait_timeout引數設定網上常見錯誤小糾

  discard connection com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet successfully receive

JVM:GC-記憶體分配回收策略

物件優先在Eden區分配 物件優先在eden區分配,當eden區沒有足夠空間分配記憶體時,就會發現minor gc. 程式碼例項: public class Main { static int _1M = 1024*1024; //vm 引數 // -ver

JVM 常用引數設定

堆設定 : 1.-Xms:初始堆大小 2.-Xmx:最大堆大小 3.-Xss:執行緒棧大小 4.-XX:NewSize=n:設定年輕代大小 5.-XX:NewRatio=n:設定年輕代和年老代的比值。如:3,表示年輕代:老年代比值為1:3,年輕代佔整總和的1/

jvm 啟動引數設定

jvm記憶體區域劃分 Eden Space、Survivor Space、Tenured Gen jvm區域總體分兩類,heap區和非heap區。heap區又分:Eden Space(伊甸園)、Survivor Space(倖存者區)、Tenured Gen

Jvm啟動引數設定

引言: 在google、baidu中輸入關鍵字,出現的連結大部分都是關於: 1、jdk提供java 命令引數說明 2、eclipse啟動引數配置(即eclipse.ini檔案的配置) 很少有一篇文章對這些引數在各個環境中的配置進行一個整體上的總結。故小生在此故弄玄虛一把,請

x210開發板uboot啟動引數設定解析--朱友鵬嵌入式課程總結

x210開發板uboot啟動引數設定與解析 1.1 映象檔案已燒錄到開發板中 1.1.1 引數設定 setenv bootcmd "movi read kernel 30008000;bootm 30008000" setenv bootargs "console=ttyS

嵌入式 SQLite3 命令列引數設定顯示引數設定

Customer text); INSERT INTO Orders(OrderPrice, Customer) VALUES(1200, 'Williamson'); INSERT INTO Orders(OrderPrice, Customer) VALUES(200, 'Robertson'); INS

引數】DB_nK_CACHE_SIZE引數設定資料庫預設塊大小之間的限制

 “DB_nK_CACHE_SIZE”引數的取值有很多種,有2k、4k、8k、16k、32k。在設定此引數時,我們需要注意的是,與資料庫預設的塊尺寸相同的那個引數是不能被設定的。例如,如果資料庫的預設塊尺寸是8k,那麼當我們嘗試設定“DB_8K_CACHE_SIZE”引數時

gc引數設定錯誤導致一直full gc

gc param JAVA_OPTS="${JAVA_OPTS} -Xms1g -Xmx1g -XX:NewSize=512m -XX:MaxNewSize=1g -Xss512k -XX:SurvivorRatio=6" JAVA_OPTS="${J

機器學習引數設定預訓練模型設定

使用tensorlayer時,出現了大量相關的引數設定,通用的引數設定如下:task = 'dcgan' flags = tf.app.flags flags.DEFINE_string('task','dcgan','this task name') flags.DEFIN

優化hbase JVM GC 引數,避免由於JVM記憶體回收引發的ZooKeeper會話超時程序退出事件

hbase預設記憶體為1G,官方文件中明確地指出這是無法支撐長時間正常執行的,是肯定要引發ZooKeeper會話超時事件,從而導致服務退出的。 文件中給出了4個不怎麼有用的建議: 加大記憶體(但不告訴加多少,反正是越多越好)確保不要使用交換分割槽(可我的硬碟是SSD,比記

JVM記憶體引數設定

在一些規模稍大的應用中,Java虛擬機器(JVM)的記憶體設定尤為重要,想在專案中取得好的效率,GC(垃圾回收)的設定是第一步。 PermGen space:全稱是Permanent Generation space.就是說是永久儲存的區域,用於存放Class和Meta

exp/imp 引數設定使用方法 (轉載)

         一. 匯出工具 exp 1. 它是作業系統下一個可執行的檔案 存放目錄/ORACLE_HOME/bin    exp匯出工具將資料庫中資料備份壓縮成一個二進位制系統檔案.可以在不同OS間遷移       它有三種模式:        a.  使用者模式:匯出使用者所有物件以及物件中的資料;

【TensorFlow】卷積神經網路的引數設定例子

一、卷積操作引數的簡要說明   如上圖所示,假設我們有32*32的RBG圖片,也就是神經網路的 input 是 32*32*3,表示輸入是一個有3個圖層的32*32的圖片。   假設現在有一個 5*5的 filter處理一個32*32的圖層,那麼處理後的