JVM參數大全詳解以及性能優化思考

#前言 
     最近回顧下JVM中的內容以備不時之需,同時也默默的在研究報名中心服務器JVM運行情況,感嘆不同場景下選擇不同的GC策略,調整JVM\GC參數,可以減少YGC、FullGC、GC種種過程中導致應用程序的中斷,同時也可以提升系統JVM性能,當然如果參數添加過多反而不會提升還會降低,所以加參數是個好習慣,但不要加不適合的參數~~。
     在來說參數之前,我要先說明下程序在運行時JVM內存的劃分,原因是參數設置不設置和不同區域的內存、策略有關,所以需要理解jvm 內存運行時期的劃分。
#JVM內存結構
     在程序運行時,JVM虛擬機在執行class文件時會把所管理的內存按照JVM虛擬機規範劃分爲五個數據區:方法區和堆,虛擬機棧、本地方法棧和程序計數器,其中方法區和堆屬於所有程序共享的數據區,一般在多線程線程安全主要的保護的區域之一,同時也是static參數對象的存放區域(運行時常量池)。
     如圖:
     
     1、程序計數器
          可以理解爲所有當前線程所執行的字節代碼的指示器。在虛擬機模型(或概念模型中)字節碼解釋器工作時就是會通過改變程序計數器來選取下一個需要執行的字節碼入分支、循環、跳轉、異常處理、線程睡眠恢復等
     2、虛擬機棧
            虛擬機棧它的生命週期是與線程相同,在程序代碼中每一個方法在執行時都會創建一個棧幀用於存儲方法中創建的內存區域,比如局部變量、操作數棧等。當這個方法執行完成之後,就代表一個棧幀從入棧到出棧的過程
           在虛擬機規範中,對虛擬機棧,固定了兩種異常,如果線程請求的棧內存大於虛擬機所允許的內存,就會拋出StackOverflowError異常,如果擴展時無法申請足夠的內存,就會拋出OutOfMemoryError異常。如果出現這兩個異常在代碼中需要檢查下那些內存溢出或者有大批量消耗內存的地方存在。 但也可以通過優化JVM參數來提高容量。
     3、本地方法棧
          本地方法棧主要是爲虛擬機使用到的Native方法服務。本地方法棧也會拋出虛擬機棧中說到的兩個異常。
    注:1、2、3說到的內容都屬於線程私有的,他們的生命週期也都與線程相同。也可以理解爲在這幾個區域存在的數據都是線程安全的。
      4、堆區
             堆區時虛擬機中內存佔比最大的一塊,是被所有線程共享的區域。同時堆野食垃圾收集器管理的重點區域,因此也會被稱爲GC堆。內存回收的角度來講,我們的垃圾收集器都是採用分代收集算法,所以java堆野可以細分爲新生代和老年代(後面很多jvm參數都是會優化這個兩個代)而在詳細劃分下又區有Eden空間、From Survivor空間和To Survivor空間。那麼在內存分配中也會劃分出線程共享的java堆中可能劃分出多個線程的私有分配緩衝區,是不是有點運簡單可以理解爲TLAB(後面也有參數對這個TLAB進行優化,而堆區主要的優化參數就是xms , xmx ,xmn ,xss)。其實無論哪個區域,存儲的都是對象實例,劃分詳細的目的也是讓jvm 更好地回收內存和分配內存。
     5、方法區
          和堆區一樣,也是多個線程共享的內存區域,由於存儲被加載的類信息。雖然有虛擬機規範會把方法區與堆描述爲一個邏輯部分,但它也可以叫爲非堆(目的是和堆區分開)
     而在運行時jvm劃分內存還有運行時常量池和直接內存區這兩部分,關於這兩部分就不細說了,有興趣的小夥伴可以自己去了解下。
#JVM參數
##基本參數
-Xms 
初始化堆大小,默認值是物理內存的1/64,物理內存總體會小於1GB,如果在空餘堆內存小於40%,JVM會自動增大堆,直到Xms的最大限制,MinHeapFreeRatio參數也是可以的調整
如:-XX:MinHeapFreeRatio=40,如果發現空閒堆內存佔到整個預估上限值的40%,則增大上限。

-Xmx
指定JAVA Heap最大堆大小,默認值是物理內存的1/4,也會小於1GB,默認在空餘堆內存大於70%時,JVM會減少堆直到-xms的最小限制,同時MaxHeapFreeRatio參數也是可以調整的;
如:-XX:MaxHeapFreeRatio=70,如果發現空閒大於70%,則減少到-xms最少限制;

-Xms與-Xmx 的單位默認字節都是以k,m做單位的

-Xmn 
年輕代大小,此處的大小是與jmap -heap 中顯示的new gen是不同的。

-Xss 
每個線程池的堆棧大小。在jdk5以上的版本,每個線程堆棧大小爲1m,jdk5以前的版本是每個線程池大小爲256k。一般在相同物理內存下,如果減少-xss值會產生更大的線程數,但不同的操作系統對進程內線程說是有限制的,是不能無限生成。

-Xmn 年輕代參數設置詳解和思考
     整個堆大小的計算公式:JVM 堆大小 = 年輕代大小+年老代大小+持久代大小。
     在增大年輕代的堆大小就會減少對應的年老代大小,設置-Xmn值對系統性能影響較大,所以如果設置年輕代大小的調整,則需要嚴格的測試調整。而年輕代是用來存放新創建的對象,大小是隨着堆大小增大和減少而有相應的變化,默認值是保持堆大小的十五分之一,-Xmn參數就是設置年輕代的大小,也可以通過-XX:NewRatio(後面也會說到)來設置年輕代與年老帶的比例,java 官方推薦配置整個堆大小爲3:8,年輕代的特點就是內存中的對象更新速度快,在短時間內容易產生大量的無用對象,如果在這個參數時就需要考慮垃圾回收器設置參數也需要調整推薦使用:複製清除算法和並行收集器進行垃圾回收,而堆年輕代的垃圾回收叫做初級回收。
     初級回收年輕代會劃分出三個區域:1新生代,2相同的復活代,在我們應用中程序只允許使用一個新生代和一個復活代,在發生垃圾回收的時候,GC會掛起程序,然後新聲代和復活代中的存活對象複製到另外一個非活動的復活代中,然後一次性清楚新生代和復活代,將原來的非活躍的復活代標記爲互動復活代。將指定次數回收後讓然存在的對象移動到年老代中,那麼在回收後,就會得到一個可用的新生代了。這也是初級回收爲什麼會劃分1新生代和2相同的復活代了。

年輕代的設置參數
-XX:NewSize  
     設置年輕代初始化的大小

-XX:MaxNewSize
     設置年輕代最大值

-XX:PermSize
     設置持久代初始值,默認是物理內存的六十四分之一

-XX:MaxPermSize 
     設置持久代最大值,默認是物理內存的四分之一

-XX:NewRatio 
      設置年輕代與年老代比值,-XX:NewRatio=4 表示年輕代與年老帶所佔比例爲1:4 ,年輕代佔比整個堆棧的五分之一。如果設置了Xms=Xmx並且設置了Xmn的情況下,該參數是不需要在設置的。

-XX:MaxTenuringThreshold
     新生代中對象存活次數,也就是說在經過GC後仍然存活,超過這個次數限制後對象會晉升到舊生代

其他參數設置輔助參
-XX:ThreadStackSIze 
     設置線程堆棧大小

-XX:SurvivorRatio 
    Eden區與Subrvivor區大小的比值,如果設置爲8,兩個Subrvivor區與一個Eden區的比值爲2:8,一個Survivor區佔整個年輕代的十分之一

-XX:LargePageSizeInBytes
   內存頁的大小,不要設置過大,否則會影響Perm的大小

-XX:+UseFastAccessorMethods 
     原始類型快速優化

-XX:+AggressiveOpts
     編譯速度加快

-XX:+DisableExplicitGC
    默認啓動,禁止在運行期顯示關閉System.gc(),如果代碼中使用此參數,需要嚴格測試啊!不要亂用否則會出故障的。。。。

-XX:+UseBiasedLocking
     優化鎖機制改善性能

-Xnoclassgc 
     禁用垃圾回收

-XX:SofLRUPolicyMSPerMB
    每兆堆空閒空間中SoftReference的存活空間,默認是1秒

-XX:PretenureSizeThreshold
     對象超過多大值時直接在舊生代中分配,

-XX:TLABWasteTargetPercent 
     TLAB佔eden區的百分比,默認是1%

-XX:+CollectGenOFist 
     FullGC時是否先YGC 默認是是false 不允許線YGC

#收集器參數
-XX:+UseSerialGC
     設置串行收集器

-XX:+UseParallelGC
    設置並行收集器, Full GC 採用parallel MSC  就是年輕代使用併發收集,而年老代仍舊使用串行收集 

-XX:+UseParNewGC
     設置年輕代爲並行收集器,這個可以與cms收集同時使用,jdk5以上是不用配置的

-XX:ParallelGCThreads 
     設置並行收集器的線程數,一般改值配置是與服務器的本身機器的cpu處理器相等,同樣也適用於cms 

-XX:+UseParalledlOldGC    
     設置並行年老代收集器, jdk6以上新出的配置

-XX:MaxGCPauseMillis 
     每次年輕代垃圾回收的最長時間,如果無法滿足此事件,JVM會自動調整年輕代大小,以滿足此值。

-XX:+UseAdaptiveSizePolicy 
     自動選擇年輕代區大小和相應的Survivor區比例,如果設置此值,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低相應時間或者手機頻率。

-XX:GCTimeRatio
     設置垃圾回收時間站程序運行時間的百分比,公式1/(1+n)

-XX:+ScavengeBeforeFullGC
     Full GC前調用YGC 默認是true 



#CMS 相關參數
-XX:+UseConcMarkSweepGC
     使用cms做內存收集器其實就是併發收集器,

-XX:+AggressiveHeap
     讓JVM自動根據機器的內存和CPU數優化各種參數,內存會使用機器最大物理內存

-XX:CMSFullGCsBeforeCompaction 
     在多少次GC後進行內存壓縮,這個是因爲並行收集器部隊內存空間進行壓縮的,所以運行一段時間後會產生很多隨便,使得運行效率降低。

-XX:+CMSParallelRemarkEnabled
     降低標記停頓

-XX:+UseCMSCompactAtFullCollection 
     在Full GC時對老年代壓縮,CMS是不會移動內存的,因此會非常容易出現碎片導致內存不夠用的

-XX:+UseCmsInitiatingOccupancyOnly 
     使用手動觸發或者自定義觸發cms 收集,同時也會禁止hostspot 自行觸發CMS GC 

-XX:CMSInitiatingOccupancyFraction 
      使用CMS作爲垃圾回收,使用70%後開始CMS收集

-XX:CMSInitiatingPermOccupancyFraction 
      設置perm gen使用達到多少%比時觸發垃圾回收,默認是92%

-XX:+CMSIncrementalMode 
     設置爲增量模式

-XX:+CmsClassUnloadingEnabled 
     CMS是不會默認對就永久代進行垃圾回收的,設置此參數則是開啓

#輔助參數
-XX:+PrintGc
     開啓簡單GC日誌模式,每一次新生代的GC和每一次的Full Gc打印一行信息

-XX:+PrintGCDetails
     開啓詳細GC日誌模式,日誌的格式是和所使用的算法有關

-XX:+PrintGCTimeStamps和-XX:+PrintGCDateStamps
     將時間和日期也加入到GC日誌中。表示JVM啓動至今的時間會被添加到每一行,如果增加後者就是在每一行就加上了絕對日期和時間。如果需要同時使用兩個參數,推薦也是使用兩個參數。
如-XX:+PrintGC:PrintGCTimeStamps,這種輔助模式也是可以放在一起使用的。

-XX:+PrintGCApplicationStoppedTime 
     打印垃圾回收器執行的暫停時間

-XX:+PrintGCApplicationConcurrentTime
     打印每次垃圾回收前,程序未中斷的執行時間

-XX:+PrintHeapAtGC
     打印GC前的詳細堆棧信息

-Xloggc:filename
     把GC日誌輸出到終端上,加上:和文件名就是輸出到某個文件中,如果使用了此參數默認就調用了-XX:+PrintGc和-XX:+PrintGCTimeStamps

-XX:+PrintClassHistogram 

-XX:+PrintTLAB
     查看TLAB空間的使用情況,還有一個useTLAB是用來啓動線程本地緩存。

-XX:+PrintTenuringDistribution 
     查看每次minor Gc後新的存活週期的閥值

-XX:-CITime
     打印在jitb編譯上的時間

-XX:ErrorFile=FileName.log 
     異常打印在錯誤文件上

-XX:+PerfSaveDataToFile
    退出時保存jvmstat二進制的文件

-XX:-HeapDumpOnOutOfMemoryError
     當拋出OOM時進行heapdump


##默認JVM啓動功能參數
-XX:+FailOverToOldVerifier 
     如果新的Class校驗器檢查失敗,則使用老的校驗器

-XX:+HandlePromotionFailure
     關閉新生代收集器,jdk5以前是不默認啓動的 jdk6默認啓用

-XX:-MaxFDLimit
     設置java 進程可用文件描述符爲操作系統允許的最大值

-XX:+ScavengeBeforeFullGC(上面有說到,Full GC前調用YGC )

-XX:+UseAltsigs
     爲了防止與其他發送信號的應用程序衝突,允許使用候補信號替代

-XX:+UseBoundTherads
     綁定所有的用戶線程到內核線程,減少線程進入到飢餓狀態次數

-XX:+UseGCOverhedLimit
     限制GC的運行時間。如果GC耗時過長,就拋OOM

-XX:+UseLWPSynchronization 
     使用輕量級進程(cpu線程)替換線程同步

-XX:+UseTLAB
     啓動線程本地緩存區

-XX:+UseSplitVerifier 
     使用新的Class類型校驗器

-XX:+UseThreadPriorities
     使用本地線程的優先級

-XX:+UseVMInterruptibleIO
     允許運行時中斷線程

##默認JVM啓動的性能優化參數
-XX:+AggressiveOpts
     JDK5 後引入的 需要手動開啓,jdk6以後自動開啓,是啓動jvm開發團隊的最新調優成果

-XX:+UseBiasedLocking
     jdk5後引入的需要手動開啓,jdk6以後默認開啓,啓動偏向鎖

-XX:+UseFastAccessorMethods
     優化原始類型的getset方法性能

-XX:-UseISM
     啓動solaris的ISM

-XX:+UseLargePages
     jdk5後引入需要手動開啓,jdk6以後默認開啓,啓動最大內存分頁

-XX:+UseMPSS
     jdk4之前不啓用,jdk4以後啓用,啓用solaris的mpss,不能與ISM同時使用

#性能優化
##參數調優 
     JVM設置堆大小是受控制的,有操作系統的數據模型控制如32還是64bt,還有系統中虛擬內存限制,系統可用物理內存限制。在32位系統下,一般內存普遍都是在2g內存之間,64位操作系統則相對可以把內存調高,理論上是可以設置到內存最大值。

##回收器選擇
     JVM有三種不同的回收器,串行收集器,並行收集器,併發收集器。串行收集器適用於數據量處理小的情況下使用,JDK5.0以前版本都是默認設置的串行收集器而串行收集器,也可以通過參數修改,在JDK6以上的版本中會根據系統配置進行判斷來選擇不同的回收器,同樣也可以自己通過參數來進行設置。收集器的實現包括有Serial收集器,ParNew收集器、Parallel Scavenge收集器,Serial old收集器、Parallel Old收集器、CMS 收集器 和 G1收集器
     那麼並行收集器和併發收集器有什麼區別?
          並行收集器是吞吐量優先,那麼如果設置了並行收集器就會以吞吐量爲目標,適用的場景就會有應用計算以及後臺的業務處理等,在我們對 並行收集器設置時,如果
          併發收集器則是以響應時間爲優先,那麼如果設置了併發收集器則是保證系統的響應時間,減少垃圾收集時的停頓時間,適用場景是Web系統等。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章