JVM虛擬機選項:Xms Xmx PermSize MaxPermSize區別(轉)


 

java啟動參數共分為三類

其一是標准參數( -),所有的JVM實現都必須實現這些參數的功能,而且向后兼容

其二是非標准參數( -X),默認jvm實現這些參數的功能,但是並不保證所有jvm實現都滿足,且不保證向后兼容

其三是非Stable參數( -XX),此類參數各個jvm實現會有所不同,將來可能會隨時取消,需要慎重使用



java雖然是自動回收內存,但是應用程序,尤其服務器程序最好根據業務情況指明內存分配限制。
否則可能導致應用程序宕掉。

舉例說明含義:
-Xms128m
表示JVM Heap(堆內存)最小尺寸128MB,初始分配
-Xmx512m
表示JVM Heap(堆內存)最大允許的尺寸256MB,按需分配。

說明:如果-Xmx不指定或者指定偏小,應用可能會導致java.lang.OutOfMemory錯誤。

IDEA中配置 -Xms  -Xmx 示例:

 




PermSize和MaxPermSize指明虛擬機為java永久生成對象(Permanate generation)
如,class對象、方法對象這些可反射(reflective)對象分配內存限制,這些內存不包括在Heap(堆內存)區之中。

-XX:PermSize=64MB 最小尺寸,初始分配
-XX:MaxPermSize=256MB 最大允許分配尺寸,按需分配
過小會導致:java.lang.OutOfMemoryError: PermGen space

MaxPermSize缺省值和-server -client選項相關。
-server選項下默認MaxPermSize為64m
-client選項下默認MaxPermSize為32m


經驗:
1、慎用最小限制選項Xms,PermSize已節約系統資源。

=========================================================

近期研究對jvm的內存使用情況進行監控,因此對觀察虛擬機的內存使用方法做了一些收集,對jvm的參數設置了解了一下:

幾個基本概念:

PermGen space:全稱是Permanent Generation space,即永久代。就是說是永久保存的區域,用於存放Class和Meta信息,Class在被Load的時候被放入該區域,GC(Garbage Collection)應該不會對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS的話,就很可能出現PermGen space錯誤。
Heap space:存放Instance。Java Heap分為3個區,Young即新生代,Old即老生代和Permanent。Young保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old區。Permanent區則負責保存反射對象。

幾個參數設置的意義:

xms/xmx:定義YOUNG+OLD段的總尺寸
ms為JVM啟動時YOUNG+OLD的內存大小
mx為最大可占用的YOUNG+OLD內存大小。
在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷


NewSize/MaxNewSize:定義YOUNG段的尺寸,
NewSize為JVM啟動時YOUNG的內存大小;
MaxNewSize為最大可占用的YOUNG內存大小。

在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。
PermSize/MaxPermSize:定義Perm段的尺寸,PermSize為JVM啟動時Perm的內存大小;MaxPermSize為最大可占用的Perm內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。
SurvivorRatio:設置YOUNG代中Survivor空間和Eden空間的比例

申請一塊內存的過程:

A. JVM會試圖為相關Java對象在Eden中初始化一塊內存區域
B. 當Eden空間足夠時,內存申請結束。否則到下一步
C. JVM試圖釋放在Eden中所有不活躍的對象(這屬於1或更高級的垃圾回收);釋放后若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區/OLD區
D. Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區
E. 當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級)
F. 完全垃圾收集后,若Survivor及OLD區仍然無法存放從Eden復制過來的部分對象,導致JVM無法在Eden區為新對象創建內存區域,則出現”out of memory錯誤”

我們的一種resin服務器的jvm參數設置:

“-Xmx2000M -Xms2000M -Xmn500M -XX:PermSize=250M -XX:MaxPermSize=250M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=60 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log”

 是一種典型的響應時間優先型的配置。

Java中有四種不同的回收算法,對應的啟動參數為
–XX:+UseSerialGC
–XX:+UseParallelGC
–XX:+UseParallelOldGC
–XX:+UseConcMarkSweepGC

1. Serial Collector
大部分平台或者強制 java -client 默認會使用這種。
young generation算法 = serial
old generation算法 = serial (mark-sweep-compact)
這種方法的缺點很明顯,stop-the-world, 速度慢。服務器應用不推薦使用。

2. Parallel Collector
在linux x64上默認是這種,其他平台要加 java -server 參數才會默認選用這種。
young = parallel,多個thread同時copy
old = mark-sweep-compact = 1
優點:新生代回收更快。因為系統大部分時間做的gc都是新生代的,這樣提高了throughput(cpu用於非gc時間)
缺點:當運行在8G/16G server上old generation live object太多時候pause time過長

3. Parallel Compact Collector (ParallelOld)
young = parallel = 2
old = parallel,分成多個獨立的單元,如果單元中live object少則回收,多則跳過
優點:old old generation上性能較 parallel 方式有提高
缺點:大部分server系統old generation內存占用會達到60%-80%, 沒有那么多理想的單元live object很少方便迅速回收,同時compact方面開銷比起parallel並沒明顯減少。

4. Concurent Mark-Sweep(CMS) Collector
young generation = parallel collector = 2
old = cms
同時不做 compact 操作。
優點:pause time會降低, pause敏感但CPU有空閑的場景需要建議使用策略4.
缺點:cpu占用過多,cpu密集型服務器不適合。另外碎片太多,每個object的存儲都要通過鏈表連續跳n個地方,空間浪費問題也會增大。

 內存監控的方法:

1.  jmap -heap pid
        查看java 堆(heap)使用情況
 
        using thread-local object allocation.
        Parallel GC with 4 thread(s)          //GC 方式

         Heap Configuration:       //堆內存初始化配置
         MinHeapFreeRatio=40     //對應jvm啟動參數-XX:MinHeapFreeRatio設置JVM堆最小空閑比率(default 40)
         MaxHeapFreeRatio=70  //對應jvm啟動參數 -XX:MaxHeapFreeRatio設置JVM堆最大空閑比率(default 70)
         MaxHeapSize=512.0MB  //對應jvm啟動參數-XX:MaxHeapSize=設置JVM堆的最大大小
         NewSize  = 1.0MB          //對應jvm啟動參數-XX:NewSize=設置JVM堆的‘新生代’的默認大小
         MaxNewSize =4095MB   //對應jvm啟動參數-XX:MaxNewSize=設置JVM堆的‘新生代’的最大大小
         OldSize  = 4.0MB            //對應jvm啟動參數-XX:OldSize=<value>:設置JVM堆的‘老生代’的大小
         NewRatio  = 8         //對應jvm啟動參數-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
         SurvivorRatio = 8    //對應jvm啟動參數-XX:SurvivorRatio=設置年輕代中Eden區與Survivor區的大小比值
          PermSize= 16.0MB       //對應jvm啟動參數-XX:PermSize=<value>:設置JVM堆的‘永生代’的初始大小
          MaxPermSize=64.0MB  //對應jvm啟動參數-XX:MaxPermSize=<value>:設置JVM堆的‘永生代’的最大大小
 
 
          Heap Usage:               //堆內存分步
          PS Young Generation
          Eden Space:          //Eden區內存分布
            capacity = 20381696 (19.4375MB)  //Eden區總容量
            used     = 20370032 (19.426376342773438MB)  //Eden區已使用
            free     = 11664 (0.0111236572265625MB)  //Eden區剩余容量
            99.94277218147106% used  //Eden區使用比率
         From Space:        //其中一個Survivor區的內存分布
             capacity = 8519680 (8.125MB)
             used     = 32768 (0.03125MB)
             free     = 8486912 (8.09375MB)
             0.38461538461538464% used
        To Space:            //另一個Survivor區的內存分布
            capacity = 9306112 (8.875MB)
            used     = 0 (0.0MB)
            free     = 9306112 (8.875MB)
            0.0% used
        PS Old Generation  //當前的Old區內存分布
            capacity = 366280704 (349.3125MB)
            used     = 322179848 (307.25464630126953MB)
            free     = 44100856 (42.05785369873047MB)
            87.95982001825573% used
        PS Perm Generation  //當前的 “永生代” 內存分布
            capacity = 3

 http://blog.sina.com.cn/s/blog_684fe8af0100v4mt.html

 

 

調試參數

打印啟動參數

可以查看默認參數

  1. java -XX:+PrintCommandLineFlags-version

打印GC日志

不要用 XX:+UseGCLogFileRotation,這個會丟失舊的日志文件,而且重啟會覆蓋當前日志文件:

  1. -XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:/home/GCEASY/gc.log -XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=5-XX:GCLogFileSize=20M

應該用下面這個

  1. -XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:/home/GCEASY/gc-%t.log

打印ClassLoader日志

這個參數會在控制台打印所有類加載/卸載信息

  1. -XX:+TraceClassLoading-XX:+TraceClassUnloading

OOM時Dump內存

  1. -XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/crashes/my-heap-dump.hprof

OOM時執行腳本(比如重啟)

  1. -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh

打印JIT時間

  1. -XX:-CITime

方法被編譯時打印相關信息

  1. -XX:-PrintCompilation

JMX

  1. -Djava.net.preferIPv4Stack=true

  2. -Dcom.sun.management.jmxremote

  3. -Djava.rmi.server.hostname={hostname}

  4. -Dcom.sun.management.jmxremote.port={port}

  5. -Dcom.sun.management.jmxremote.authenticate=false

內存類

JVM設置內存的單位默認是字節(不加單位的情況下)。

也可以在大小后面增加單位,例如:

  1. -Xmn256m

  2. -Xmn262144k

  3. -Xmn268435456

設置初始新生代大小

  1. -XX:NewSize=2G(也可以是2M)

設置最大新生代大小

  1. -XX:MaxNewSize=2G(也可以是2M)

注意:-Xmn優先級大於-XX:NewRatio

設置Eden/Survivor比例

表示兩個Survivor和Edgen區的比,8表示兩個Survivor:Eden=2:8,即一個Survivor占新生代的1/10。

計算方式為:

  1. SurvivorSize(1) = YoungGenerationSize/ (2+<SurvivorRatio)

  2. EdenSize= YoungGenerationSize/ (2+SurvivorRatio) * SurvivorRatio

配置:

  1. -XX:SurvivorRatio=8

8也是默認的比例,不過這個比例在Parallel Scavenge(新生代並行回收器,JDK5以后的默認新生代回收器)回收器下是動態的,運行時會出現Eden/Survivor比例和配置的不同。整編:微信公眾號,搜雲庫技術團隊,ID:souyunku

由於與吞吐量關系密切,Parallel Scavenge收集器也經常稱為“吞吐量優先”收集器。除上述兩個參數之外,Parallel Scavenge收集器還有一個參數-XX:+UseAdaptiveSizePolicy值得關注。這是一個開關參數,當這個參數打開之后,就不需要手工指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉升老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大的吞吐量,這種調節方式稱為GC自適應的調節策略(GC Ergonomics)[插圖]。如果讀者對於收集器運作原來不太了解,手工優化存在困難的時候,使用Parallel Scavenge收集器配合自適應調節策略,把內存管理的調優任務交給虛擬機去完成將是一個不錯的選擇。只需要把基本的內存數據設置好(如-Xmx設置最大堆),然后使用MaxGCPauseMillis參數(更關注最大停頓時間)或GCTimeRatio (更關注吞吐量)參數給虛擬機設立一個優化目標,那具體細節參數的調節工作就由虛擬機完成了。自適應調節策略也是Parallel Scavenge收集器與ParNew收集器的一個重要區別。

https://docs.oracle.com/javas...

設置老年代大小

老年代大小無法直接設置,只能通過堆大小+分配比例進行調整

  1. #設置新老一代大小之間的比率。默認值為2。2表示New Size:Old Size=1:2,則新生代占堆大小的1/3,老年代占堆大小的2/3

  2. -XX:NewRatio=2

新生代老年代大小計算方式為:

  1. NewSize= HeapSize/ NewRatio+ 1

  2. OldSize= (HeapSize/ NewRatio+ 1) * NewRatio

設置永久代(PermGen/MetaSpace)大小

  1. #設置分配給永久生成的空間,如果超出該空間,則會觸發垃圾回收。此選項在JDK 8中已棄用,並由-XX:MetaspaceSize選項取代。

  2. -XX:PermSize=size

  3. #設置最大永久生成空間大小(以字節為單位)。此選項在JDK 8中已棄用,並由-XX:MaxMetaspaceSize選項取代。

  4. -XX:MaxPermSize=size

  5.  

  6. #設置分配的Metaspace的大小,Metaspace將在首次超過垃圾收集時觸發垃圾收集。垃圾收集的閾值取決於使用的元數據量而增加或減少。默認大小取決於平台。

  7. -XX:MetaspaceSize=size

  8.  

  9. #設置可以分配給Metaspace的最大本機內存。默認情況下,大小不受限制。應用程序的Metaspace量取決於應用程序本身,其他正在運行的應用程序以及系統上可用的內存量

  10. -XX:MaxMetaspaceSize=size

初始大小和最大值的區別

初始值(比如 -Xms)為JVM啟動是向操作系統申請的內存大小( malloc),最大值(比如 -Xmx)表示,當使用的內存超過初始值后擴容的最大值

PS: JVM配置了多少內存並不是說啟動后就會占用多少物理內存,因為操作系統的內存分配是惰性的。對於已申請的內存雖然會分配地址空間,但並不會直接占用物理內存,真正使用的時候才會映射到實際的物理內存。

GC類

 

 

這里說一下PermGen/Metaspace的GC,沒有查到官方資料說永久代的固定垃圾回收器,但是在stackoverflow上有人回答到:

所有垃圾回收器都會回收永久代,包括PS/CMS,但並不是每個GC周期都會清理永久代。

這個不用糾結,看GC日志里清理的信息即可。

Serial/Serial Old

最古老的,單線程,獨占式,成熟,每次GC會STW,適合單CPU 服務器

Serial是一個新生代收集器,Serial Old是Serial收集器的的老年代版本

新生代和老年代都用串行收集器

  1. -XX:+UseSerialGC

新生代使用ParallerGC,老年代使用Serial Old

  1. -XX:+UseParallelGC

ParNew

和Serial基本沒區別,唯一的區別:多線程,多CPU的,停頓時間比Serial少

新生代使用ParNew,老年代使用Serial Old

  1. -XX:+UseParNewGC(在Java8中已棄用,在Java9中已刪除)

Parallel Scavenge(ParallerGC)/Parallel Old

關注吞吐量的垃圾收集器,高吞吐量則可以高效率地利用CPU時間,盡快完成程序的運算任務,主要適合在后台運算而不需要太多交互的任務。整編:微信公眾號,搜雲庫技術團隊,ID:souyunku

所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機總共運行了100分鍾,其中垃圾收集花掉1分鍾,那吞吐量就是99%。

Parallel Scavenge是一個新生代收集器,Parallel Old是Parallel Scavenge收集器的的老年代版本

新生代使用ParallerGC,老年代使用Parallel Old

  1. -XX:+UseParallelGC

  2. #等價於

  3. -XX:+UseParallelOldGC

Concurrent Mark Sweep (CMS)

CMS(Concurrent Mark Sweep),收集器是一種以獲取最短回收停頓時間為目標的收集器,一個老年代垃圾回收器。目前很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給用戶帶來較好的體驗。CMS收集器就非常符合這類應用的需求。

新生代使用ParNew,老年代的用CMS

  1. -XX:+UseConcMarkSweepGC

G1

使用G1收集器

  1. -XX:+UseG1GC

垃圾回收器的組合

 

 

下面是一些缺省的寫法

 

 

JDK7

  1. JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "

  2. JAVA_DEBUG_OPTS=" -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh "

JDK8

  1. JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:MetaspaceSize=256m -Xss1024m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "

  2. JAVA_DEBUG_OPTS=" -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/GCEASY/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh "

關於G1,雖然說JDK8中已經支持G1了,但是並不是說一定需要。

G1的重要特點是為用戶的應用程序的提供一個低GC延時和大內存GC的解決方案,適用於大內存場景(官方推薦堆6G以上)

如果程序正在使用CMS或ParallelOld垃圾回收器,並且具有一個或多個以下特征,那么則可以考慮升級為G1:

  • Full GC持續時間太長或太頻繁

  • 對象分配率或年輕代升級老年代很頻繁

  • 垃圾收集時間或壓縮暫停(超過0.5至1秒)時間過長

PS:如果正在使用CMS或ParallelOld收集器,並且程序沒有遇到長時間的垃圾收集暫停,那么就不需要升級到G1

作者:空無

來源:http://suo.im/5Y8mTF

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM