JVM 調優
JVM 堆內存分區
堆:年輕代,老年代,持久代
年輕代:Eden,Survivor1,Survivor2
JVM基本回收算法
-
引用計數(Reference Counting)
比較古老的回收算法。原理是此對象有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只用收集計數為0的對象。此算法最致命的是無法處理循環引用的問題。 -
標記-清除(Mark-Sweep)
此算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法需要暫停整個應用,同時,會產生內存碎片。 -
復制(Copying)
此 算法把內存空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象復制到另外一個區域中。次算法每次只處理 正在使用中的對象,因此復制成本比較小,同時復制過去以后還能進行相應的內存整理,不過出現“碎片”問題。當然,此算法的缺點也是很明顯的,就是需要兩倍 內存空間。 -
標記-整理(Mark-Compact)
此算法結 合了“標記-清除”和“復制”兩個算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把清除未標記對象并且把存活 對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-清除”的碎片問題,同時也避免了“復制”算法的空間問題。 -
增量收集(Incremental Collecting)
實施垃圾回收算法,即:在應用進行的同時進行垃圾回收。不知道什么原因JDK5.0中的收集器沒有使用這種算法的。 -
分代(Generational Collecting)
基于對對象生命周期分析后得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命周期的對象使用不同的算法(上述方式中的一個)進行回收。現在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。
JVM常見配置匯總
-
堆設置
-
-Xms:初始堆大小(默認值,物理內存的1/64)
-
-Xmx:最大堆大小(默認值,物理內存的1/4)
-
-Xmn:年輕代大小(Sun官方推薦年輕代配置為整個堆的3/8)
-
-XX:NewSize=n:設置年輕代大小
-
-XX:MaxNewSize=n:設置年輕代最大值
-
-XX:NewRatio=n:設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4。
-
-XX:PermSize=n:設置持久代的大小 (物理內存的1/64)
-
-XX:MaxPermSize=n:設置持久代大小最大值(物理內存的1/4)
-
-XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區占整個年輕代的1/5
-
-Xss:每個線程的堆棧大小,JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K.更具應用的線程所需內存大小進行 調整.在相同物理內存下,減小這個值能生成更多的線程.
-
-XX:+UseBiasedLocking:鎖機制性能改善
-
收集器設置
-
-XX:+UseSerialGC:設置串行收集器
-
-XX:+UseParallelGC:設置并行收集器 (此配置僅對年輕代有效)
-
-XX:+UseParalledlOldGC:設置并行年老代收集器
-
-XX:+UseConcMarkSweepGC:設置并發收集器(參數表示對于老年代的回收采用CMS。CMS采用的基礎算法是:標記—清除。)
-
-XX:ParallelGCThreads=n:設置并行收集器線程數,此值最好與處理器核數相同
-
-XX:MaxGCPauseMillis=n:設置并行收集最大暫停時間(每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值.)
-
XX:GCTimeRatio=n:設置垃圾回收時間占程序運行時間的百分比。公式為1/(1+n)
-
垃圾回收統計信息
-
-XX:+PrintGC
-
-XX:+PrintGCDetails
-
-XX:+PrintGCTimeStamps
-
-Xloggc:filename
-
并發收集器設置
-
-XX:+CMSIncrementalMode:設置為增量模式。適用于單CPU情況。
-
-XX:ParallelGCThreads=n:設置并發收集器年輕代收集方式為并行收集時,使用的CPU數。并行收集線程數。
常見配置:
請看一下一個時間的Java參數配置:(服務器:Linux 64Bit,8Core×16G)
JAVA_OPTS="$JAVA_OPTS -server -Xms3G -Xmx3G -Xss256k
-XX:PermSize=128m
-XX:MaxPermSize=128m
-XX:+UseParallelOldGC
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/aaa/dump
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/usr/aaa/dump/heap_trace.txt
-XX:NewSize=1G
-XX:MaxNewSize=1G"
調優總結
-
年輕代大小選擇
-
響應時間優先的應用:盡可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇)。在此種情況下,年輕代收集發生的頻率也是最小的。同時,減少到達年老代的對象。
-
吞吐量優先的應用:盡可能的設置大,可能到達Gbit的程度。因為對響應時間沒有要求,垃圾收集可以并行進行,一般適合8CPU以上的應用。
-
年老代大小選擇
-
響應時間優先的應用:年老代使用并發收集器,所以其大小需要小心設置,一般要考慮并發會話率和會話持續時間等一些參數。如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。最優化的方案,一般需要參考以下數據獲得:
-
并發垃圾收集信息
-
持久代并發收集次數
-
傳統GC信息
-
花在年輕代和年老代回收上的時間比例
-
減少年輕代和年老代花費的時間,一般會提高應用的效率
-
吞吐量優先的應用:一般吞吐量優先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以盡可能回收掉大部分短期對象,減少中期的對象,而年老代盡存放長期存活對象。
-
CMS調優可針對老年代
-
較小堆引起的碎片問題
因為年老代的并發收集器使用標記、清除算法,所以不會對堆進行壓縮。當收集器回收時,他會把相鄰的空間進行 合并,這樣可以分配給較大的對象。但是,當堆空間較小時,運行一段時間以后,就會出現“碎片”,如果并發收集 器找不到足夠的空間,那么并發收集器將會停止,然后使用傳統的標記、清除方式進行回收。如果出現“碎片”,可 能需要進行如下配置:
-
-XX:+UseCMSCompactAtFullCollection:使用并發收集器時,開啟對年老代的壓縮。
-
-XX:CMSFullGCsBeforeCompaction=0:上面配置開啟的情況下,這里設置多少次Full GC后,對年老代進行壓縮
一個性能較好的web服務器jvm參數配置:
-server//服務器模式
-Xmx2g //JVM最大允許分配的堆內存,按需分配
-Xms2g //JVM初始分配的堆內存,一般和Xmx配置成一樣以避免每次gc后JVM重新分配內存。
-Xmn256m //年輕代內存大小,整個JVM內存=年輕代 + 年老代 + 持久代
-XX:PermSize=128m //持久代內存大小
-Xss256k //設置每個線程的堆棧大小
-XX:+DisableExplicitGC //忽略手動調用GC, System.gc()的調用就會變成一個空調用,完全不觸發GC
-XX:+UseConcMarkSweepGC //并發標記清除(CMS)收集器
-XX:+CMSParallelRemarkEnabled //降低標記停頓
-XX:+UseCMSCompactAtFullCollection //在FULL GC的時候對年老代的壓縮
-XX:LargePageSizeInBytes=128m //內存頁的大小
-XX:+UseFastAccessorMethods //原始類型的快速優化
-XX:+UseCMSInitiatingOccupancyOnly //使用手動定義初始化定義開始CMS收集
-XX:CMSInitiatingOccupancyFraction=70 //使用cms作為垃圾回收使用70%后開始CMS收集