JVM性能調優1:JVM性能調優理論及實踐(收集整理)

本系列包括:java

JVM性能調優1:JVM性能調優理論及實踐(收集整理)程序員

JVM性能調優2:JVM性能調優參數整理web

JVM性能調優3:JVM_堆溢出分析過程和命令算法

JVm性能調優4:GC日誌分析windows

JVM性能調優5:Heap堆分析方法數組

 

 

注:本文部份內容收集整理了網上的資料。緩存

1.      內存結構服務器

1.1.     分代結構圖網絡

注意:多線程

在JVM中,非堆內存,根據模式不一樣分爲不一樣的幾個部分。

-Server下:非堆包括:持久代和代碼緩存(Code cache)

-client下:非堆包括:持久代、代碼緩存(Code cache)、Perm rw和perm ro。

2.      性能指標

對於垃圾收集的性能,主要有兩個指標。

吞吐量(throughput)指用來進行垃圾收集以外工做所用的時間佔總時間的百分比,通常要經過長時間的觀察和測量。吞吐量包括了分配內存所花費的時間在內(通常來講無需對分配進行調優)。

Throughput is the percentage of total time not spent in garbage collection,considered over long periods of time. Throughput includes time spent inallocation (but tuning for speed of allocation is generally not needed.) (from《Tuning GC with jdk 1.5》)

 

暫停(Pause)指因爲進行垃圾收集而致使應用沒法響應的時間。

Pauses are the times when an application appears unresponsive becausegarbage collection is occurring.

Footprint is the working set of a process, measured in pages and cachelines. On systems with limited physical memory or many processes, footprint maydictate scalability.      Promptnessis the time between when an object becomes dead and when the memory becomesavailable, an important consideration for distributed systems, including remotemethod invocation (RMI). (from《Tuning GC with jdk 1.5》)

用戶對於垃圾收集有不一樣的需求,例如,對於Web服務器應用來講,吞吐量是要着重考慮的,而暫停時間可能因爲網絡的反應時間而不那麼明顯;而對於一個交互式圖形界面的應用來講,即便是短暫的暫停都會帶來很是很差的用戶體驗。

In general, aparticular generation sizing chooses a trade-off between these considerations.For example, a very largeyoung generation may maximize throughput,but does so at the expense of footprint, promptness, and pause times.younggeneration pauses can be minimized by using a smallyoung generationat the expense of throughput. To a first approximation, the sizing of onegeneration does not affect the collection frequency and pause times for anothergeneration .(from《Tuning GC with jdk 1.5》)

一般來講,如何設置代的大小是在這些考慮因素之間做出的一個權衡。例如,將新生代設置得很大會獲得很好的吞吐性能,可是會增長暫停時間;反之,較小的新生代設置會減少暫停時間,可是下降了吞吐量。

一個代的大小不該該影響在其餘代上進行垃圾收集的頻率和暫停時間。

 

3.      引用類型

對象引用類型分爲強引用、軟引用、弱引用和虛引用

3.1.     強引用

就是咱們通常聲明對象是時虛擬機生成的引用,強引用環境下,垃圾回收時須要嚴格判斷當前對象是否被強引用,若是被強引用,則不會被垃圾回收。

3.2.     軟引用

軟引用通常被作爲緩存來使用。與強引用的區別是,軟引用在垃圾回收時,虛擬機會根據當前系統的剩餘內存來決定是否對軟引用進行回收。若是剩餘內存比較緊張,則虛擬機會回收軟引用所引用的空間;若是剩餘內存相對富裕,則不會進行回收。換句話說,虛擬機在發生OutOfMemory時,確定是沒有軟引用存在的。

3.3.     弱引用

弱引用與軟引用相似,都是做爲緩存來使用。但與軟引用不一樣,弱引用在進行垃圾回收時,是必定會被回收掉的,所以其生命週期只存在於一個垃圾回收週期內。

3.4.     虛引用

 

4.      內存分配回收次序

新生代是類的誕生、成長、消亡的區域,一個類在這裏產生,應用,最後被垃圾回收器收集,結束生命。

新生區又分爲兩部分:伊甸區(Eden space)和倖存者區(Survivorpace),全部的類都是在enden被new出來的。倖存區有兩個: 0區(Survivor 0 space)和1區(Survivor 1 space)。

當Eden的空間用完時,程序又須要建立對象,JVM的垃圾回收器將對enden區進行垃圾回收,將enden區中的再也不被其餘對象所引用的對象進行銷燬(次收集)。

而後將伊甸園中的剩餘對象移動到倖存0區。若倖存0區也滿了,再對該區進行垃圾回收(次收集),而後移動到1區。那若是1區也滿了呢?(次收集)

再移動到養老區。

新生代採用複製算法,old區採用標記清除算法。

不管是複製算法仍是標記清除算法,在垃圾收集期間都要暫停客戶的應用程序(cms垃圾收集器除外,它在初始標記和從新標記時暫停,併發標記和併發清除時,客戶線程不暫停)。

不管是複製算法仍是標記清除算法,在最開始,倒要標記活動的對象,即對象的可達性分析,在這裏,必需要求對象是一致的(便可達性分析期間,內存狀態是凍結的);在cms收集器是,在初始標記(對root對象標記時,要求凍結)凍結,但此時會產生浮動垃圾,即在併發標記時,由分配了新的對象(由於沒有凍結)。

綜述,基本過程是,複製算法:標記(暫停)-->複製(暫停,因對象地址發生變化);標記清除整理算法:標記(暫停)-->清除整理(消除碎片,暫停,因對象地址發生變化)。

對root對象標記很快,對內存掃描分析,可達性分析過程很慢。清除很慢(內存回收),內存整理、複製(慢)。

內存分配須要時間。

 

5.      對象標記算法(Object Marking Algorithms

5.1.     引用計數法(ReferenceCounting)

堆中每個對象都有一個引用計數。當新建立一個對象,或者有變量被賦值爲這個對象的引用,則這個對象的引用計數加1;當一個對象的引用超過生存期或者被設置一個新的值時,這個對象的引用計數減1。當對象的引用計數變爲0時,就能夠被看成垃圾收集。

這種方法的好處是垃圾收集較快,適用於實時環境。缺點是這種方法沒法監測出循環引用。例如對象A引用對象B,對象B也引用對象A,則這兩個對象可能沒法被垃圾收集器收集。所以這種方法是垃圾收集的早期策略,如今不多使用。

5.2.     根搜索算法(Garbage Collection Roots Tracing)

5.2.1.    基本思想

這種方法把每一個對象看做圖中一個節點,對象之間的引用關係爲圖中各節點的鄰接關係。垃圾收集器從一個或數個根結點遍歷對象圖,若是有些對象節點永遠沒法到達,則這個對象能夠被看成垃圾回收。

容易發現,這種方法能夠檢測出循環引用,避免了引用計數法的缺點,較爲經常使用。步驟以下:

  1. 選定一些對象,做爲 GC Roots,組成基對象集;

  2. 由基對象集內的對象出發,搜索全部可達的對象;

  3. 其他的不可達的對象,就是能夠被回收的對象。

    這裏的「可達」與「不可達」與圖論中的定義同樣,全部的對象被看作點,引用被看作有向鏈接,整個引用關係就是一個有向圖。在「引用計數法」中提到的循環引用,其實就是有向圖中有環的狀況,即構成「有向有環圖」。引用計數法不適用於「有向有環圖」,而根搜索算法適用於全部「有向圖」,包括有環的和無環的。

5.2.2.    GCRoots

若是你的邏輯思惟夠清晰,你會說「必定與選取基對象集的方法有關」。是的,沒錯。選取 GC Roots 組成基對象集,其實就是選取以下這些對象:

《深刻理解 Java 虛擬機:JVM高級特性與最佳實踐》一書中提到的 GC Roots 爲:

 

1.     方法區(Method Area,即 Non-Heap)中的類的 static 成員引用的對象,和 final成員引用的對象;

2.     Java方法棧(Java Method Stack)的局部變量表(Local Variable Table)中引用的對象;

3.     原生方法棧(Native Method Stack)中 JNI中引用的對象。

但顯然不夠全面,[參考2]中提到的要更全面:(March 6th,2012 update

1.     由系統類加載器加載的類相應的對象:這些類永遠不會被卸載,且這些類建立的對象都是 static 的。注意用戶使用的類加載器加載的類建立的對象,不屬於 GC Roots,除非是 java.lang.Class 的相應實例有可能會稱爲其餘類的 GC Roots。

2.     正在運行的線程。

3.     Java方法棧(Java Method Stack)的局部變量表(Local Variable Table)中引用的對象。

4.     原生方法棧(Native Method Stack)的局部變量表(Local Variable Table)中引用的對象。

5.     JNI中引用的對象。

6.     同步監控器使用的對象。

7.     由 JVM 的 GC控制的對象:這些對象是用於 JVM內部的,是實現相關的。通常狀況下,可能包括系統類加載器(注意與「1」不同,「1」中是 objects created by the classes loaded bysystem class loaders,這裏是 theobjects, corresponding instances of system class loaders)、JVM內部的一些重要的異常類的對象、異常句柄的預分配對象和在類加載過程當中自定義的類加載器。不幸的是,JVM並不提供這些對象的任何額外的詳細信息。所以這些實現相關的內容,須要依靠分析來斷定。

因此這個算法實施起來有兩部分,第一部分就是到 JVM 的幾個內存區域中「找對象」,第二部分就是運用圖論算法

 

6.      垃圾回收算法

6.1.     標記-清除(Mark-Sweep)

此算法執行分兩階段。第一階段從引用根節點開始標記全部被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法須要暫停整個應用,同時,會產生內存碎片。

6.2.     標記-整理(Mark-Compact)

此算法結合了「標記-清除」和「複製」兩個算法的優勢。也是分兩階段,第一階段從根節點開始標記全部被引用對象,第二階段遍歷整個堆,把清除未標記對象而且把存活對象「壓縮」到堆的其中一塊,按順序排放。此算法避免了「標記-清除」的碎片問題,同時也避免了「複製」算法的空間問題。

6.3.     複製(Copying)

此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另一個區域中。次算法每次只處理正在使用中的對象,所以複製成本比較小,同時複製過去之後還能進行相應的內存整理,不會出現「碎片」問題。固然,此算法的缺點也是很明顯的,就是須要兩倍內存空間

6.4.     增量收集算法

增量收集器把堆棧分爲多個域,每次僅從一個域收集垃圾。這會形成較小的應用程序中斷。

6.5.     分代收集算法

這種收集器把堆棧分爲兩個或多個域,用以存放不一樣壽命的對象。虛擬機生成的新對象通常放在其中的某個域中。過一段時間,繼續存在的對象將得到使用期並轉入更長壽命的域中。分代收集器對不一樣的域使用不一樣的算法以優化性能。這樣能夠減小複製對象的時間。

6.6.     併發收集算法

併發收集器與應用程序同時運行。這些收集器在某點上(好比壓縮時)通常都不得不中止其餘操做以完成特定的任務,可是由於其餘應用程序可進行其餘的後臺操做,因此中斷其餘處理的實際時間大大下降。

6.7.     並行收集器

並行收集器使用某種傳統的算法並使用多線程並行的執行它們的工做。在多CPU機器上使用多線程技術能夠顯著的提升java應用程序的可擴展性。

6.8.     自適應收集器

根據程序運行情況以及堆的使用情況,自動選一種合適的垃圾回收算法。這樣能夠不侷限與一種垃圾回收算法。

6.9.     火車增量算法

垃圾收集算法一個很大的缺點就是難以控制垃圾回收所佔用的CPU時間,以及什麼時候須要進行垃圾回收。火車算法是分代收集器所用的算法,目的是在成熟對象空間中提供限定時間的漸進收集。目前應用於SUN公司的Hotspot虛擬機上。

在火車算法中,內存被分爲塊,多個塊組成一個集合。爲了形象化,一節車箱表明一個塊,一列火車表明一個集合,見圖一

 

圖一

注意每一個車箱大小相等,但每一個火車包含的車箱數不必定相等。垃圾收集以車箱爲單位,收集順序依次爲1.1,1.2,1.3,1.4,2.1,2.2,2.3,3.1,3.2,3.3。這個順序也是塊被建立的前後順序。

垃圾收集器先從塊1.1開始掃描直到1.4,若是火車1四個塊中的全部對象沒有被火車2和火車3的對象引用,而只有火車1內部的對象相互引用,則整個火車1都是垃圾,能夠被回收。

如圖二,車箱1.1中有對象A和對象B,1.3中有對象C,1.4中有對象D,車箱2.2中有對象E,車箱3.3中有對象F。在火車1中,對象C引用對象A,對象B引用對象D,可見,火車2和火車3沒有引用火車1的對象,則整個火車1都是垃圾。

圖二

 

若是火車1中有對象被其它火車引用,見圖三,掃描車箱1.1時發現對象A被火車2中的E引用,則將對象A從車箱1.1轉移到車箱2.2,而後掃描A引用的對象D,把D也轉移到車箱2.2,而後掃描D,看D是否引用其它對象,若是引用了其它對象則也要轉移,依次類推。掃描完火車1的全部對象後,剩下的沒有轉移的對象都是垃圾,能夠把整個火車1都做爲垃圾回收。注意若是在轉移時,若是車箱2.2空間滿了,則要在火車2末尾開闢新的車箱2.4,將新轉移的對象都放到2.4,即火車的尾部)

圖三

補充說明:垃圾回收器一次只掃描一個車箱。圖三中的對象B與C並非當即被回收,而是先會被轉移到火車1的尾部車箱。即掃描完1.1後,B被轉移到火車1尾部,掃描完1.3後,C被轉移到車尾。等垃圾收集器掃描到火車1尾部時,若是仍然沒有外部對象引用它們,則B和C會被收集。

火車算法最大的好處是它能夠保證大的循環結構能夠被徹底收集,由於成爲垃圾的循環結構中的對象,不管多大,都會被移入同一列火車,最終一塊兒被收集。還有一個好處是這種算法在大多數狀況下能夠保證一次垃圾收集所耗時間在必定限度以內,由於一次垃圾回收只收集一個車箱,而車箱的大小是有限度的。

 

7.      觸發垃圾收集的條件

因爲對象進行了分代處理,所以垃圾回收區域、時間也不同。GC有兩種類型:Scavenge GC和Full GC。

7.1.     次收集ScavengeGC

通常狀況下,當Enden區對象已滿,或當新對象生成,而且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,而且把尚且存活的對象移動到Survivor區。而後整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。由於大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,因此Eden區的GC會頻繁進行。於是,通常在這裏須要使用速度快、效率高的算法,使Eden去能儘快空閒出來。

對Survivor區,當達到設置的預約值(默認50%),則進行一次垃圾次收集。

7.2.     全收集FullGC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC由於須要對整個對進行回收,因此比Scavenge GC要慢,所以應該儘量減小Full GC的次數。在對JVM調優的過程當中,很大一部分工做就是對於FullGC的調節。有以下緣由可能致使Full GC:

·年老代(Tenured)被寫滿

·持久代(Perm)被寫滿

· System.gc()被顯示調用

·上一次GC以後Heap的各域分配策略動態變化

 

8.      垃圾收集器類型

8.1.     串行收集器

用單線程處理全部垃圾回收工做,由於無需多線程交互,因此效率比較高。可是,也沒法使用多處理器的優點,因此此收集器適合單處理器機器。固然,此收集器也能夠用在小數據量(100M左右)狀況下的多處理器機器上。可使用-XX:+UseSerialGC打開。

8.2.     並行收集器

注:圖有問題,是併發垃圾收集器的圖。

並行垃圾回收,所以能夠減小垃圾回收時間。通常在多線程多處理器機器上使用。

8.3.     併發垃圾收集

併發收集器主要減小年老代的暫停時間,他在應用不中止的狀況下使用獨立的垃圾回收線程,跟蹤可達對象。在每一個年老代垃圾回收週期中,在收集初期併發收集器會對整個應用進行簡短的暫停,在收集中還會再暫停一次。第二次暫停會比第一次稍長,在此過程當中多個線程同時進行垃圾回收工做。

浮動垃圾:因爲在應用運行的同時進行垃圾回收,因此有些垃圾可能在垃圾回收進行完成時產生,這樣就形成了「Floating Garbage」,這些垃圾須要在下次垃圾回收週期時才能回收掉。因此,併發收集器通常須要20%的預留空間用於這些浮動垃圾。

Concurrent Mode Failure:併發收集器在應用運行時進行收集,因此須要保證堆在垃圾回收的這段時間有足夠的空間供程序使用,不然,垃圾回收還未完成,堆空間先滿了。這種狀況下將會發生「併發模式失敗」,此時整個應用將會暫停,進行垃圾回收。

啓動併發收集器:由於併發收集在應用運行時進行收集,因此必須保證收集完成以前有足夠的內存空間供程序使用,不然會出現「Concurrent Mode Failure」。經過設置-XX:CMSInitiatingOccupancyFraction=<N>指定old區達到百分之多少時開始執行併發收集。

9.      垃圾收集器介紹

9.1.     串行垃圾收集

Serial Collector是指任什麼時候刻都只有一個線程進行垃圾收集,這種策略有一個名字「stop the whole world",它須要中止整個應用的執行。這種類型的收集器適合於單器CPU的機器。

Serial Copying Collector

此種GC用-XX:UseSerialGC選項配置,它只用於新生代對象的收集。1.5.0之後.

-XX:MaxTenuringThreshold來設置對象複製的次數。當eden空間不夠的時候,GC會將eden的活躍對象和一個名叫From survivor空間中尚不夠資格放入Old代的對象複製到另一個名字叫To Survivor的空間。而此參數就是用來講明到底From survivor中的哪些對象不夠資格,假如這個參數設置爲31,那麼也就是說只有對象複製31次之後纔算是有資格的對象。

這裏須要注意幾個個問題:

  • From Survivor和To survivor的角色是不斷的變化的,同一時間只有一塊空間處於使用狀態,這個空間就叫作From Survivor區,當複製一次後角色就發生了變化。

  • 若是複製的過程當中發現To survivor空間已經滿了,那麼就直接複製到old generation.

  • 比較大的對象也會直接複製到Old generation,在開發中,咱們應該儘可能避免這種狀況的發生。

     

     

    並行垃圾收集(Parallel Collector)

    Parallel Copying Collector

    -XX:+UseParNewGC用來設置年輕代爲併發收集【多CPU】,若是你的服務器有多個CPU,你能夠開啓此參數;開啓此參數,多個CPU可併發進行垃圾回收,可提升垃圾回收的速度。此參數和-XX:ParallelGCThreads搭配使用。適用於1.4之後版本。

 

Parallel Mark-Compact Collector

此種GC用-XX:+UseParallelOldGC參數配置,此GC主要用於老生代對象的收集。適用於1.6.0之後版本。

 

Parallel scavenging Collector

-XX:+UseParallelGC它是對新生代對象的垃圾收集器。年輕代使用並行收集,而年老代仍舊使用串行收集。可提升系統的吞吐量。此參數和-XX:ParallelGCThreads搭配使用。適用於1.4之後版本。它比較適合於對吞吐量高於暫停時間的場合。

採用多線程並行(Parallel)進行垃圾收集。

 

9.3.     併發垃圾收集器(Concurrent Collector)

此種GC能夠用參數-XX:+UseConcMarkSweepGC配置,此GC主要用於老生代和Perm代的收集。

Concurrent Collector經過併發的方式進行垃圾收集,這樣就減小了垃圾收集器收集一次的時間,這種GC在實時性要求高於吞吐量的時候比較有用。

在應用運行的同時,併發(Concurrent)進行垃圾收集。

  1. 配置垃圾回收線程數量

             -XX:ParallelGCThreads年輕代並行垃圾收集的前提下(對併發也有效果)的線程數,增長並行度,即:同時多少個線程一塊兒進行垃圾回收。此值最好配置與處理器數目相等。
    例如:-XX:ParallelGCThreads=2

  2. 配置垃圾收集器須要注意的地方

    垃圾收集器不可重複配置,例如已經配置了新生代並行收集(-XX:+UseParNewGC),此時不能配置任何對新生代的垃圾收集。能夠配置對舊生代和持久對象的垃圾收集。

    例如:

    -XX:+UseParNewGC-XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=2

    可組合適用。

    增量

    配合併發垃圾收集,適用於單cpu的架構,sun不建議使用。

     

    自適應

    自適應垃圾收集,運行在並行垃圾收集上。在並行收集時對於收集時間、分配比例、收集以後堆的空閒空間等數據進行統計分析,而後以此爲依據調整新生代和舊生代的大小以達到最佳效果。

     

     

    小結

             從J2SE平臺1.4.2版本開始,加入了另外3種垃圾收集器,都是着重提升吞吐能力,下降垃圾收集時的暫停時間。

             1. 吞吐收集器(throughput collector):命令行參數:-XX:+UseParallelGC。在新生代使用並行收集策略,在舊生代和默認收集器相同。

             吞吐收集器和默認的收集器相似,都是分代收集器。不一樣之處就在於吞吐收集器用多線程進行次要收集,

            從J2SE平臺1.4.1版本開始,吞吐收集器就具備了一個特徵,就是大小自適應(參數-XX:

    +UseAdaptiveSizePolicy),這個選項默認是打開的。該特徵對於收集時間、分配比例、收集以後   堆的空閒空間等數據進行統計分析,而後以此爲依據調整新生代和舊生代的大小以達到最佳效果。可使用-verbose:gc來查看堆的大小。

             -XX:+AggressiveHeap選項會檢測主機的資源(內存大小、處理器數量),而後調整相關的參數,使得長時間運行的、內存申請密集的任務可以以最佳狀態運行。該選項最初是爲擁有大量內存和不少處理器的主機而設計的,可是從J2SE1.4.1以及其後繼版原本看,即便是對於那些只有4顆CPU的       主機,該選項都是頗有幫助的。所以,吞吐收集器(-XX:+UseParallelGC)、大小自適應 (-XX:+UseAdaptiveSizePolicy)以及本選項(-XX:+AggressiveHeap)常常結合在一塊兒使用。要使    用本選項,主機上至少要有256M的物理內存,堆內存的最初大小是基於物理內存計算出來的,而後 會根據須要儘量的利用物理內存。

           2. 併發收集器(concurrent low pause collector):命令行參數:-XX:+UseConcMarkSweepGC。在舊生代使用併發收集策略,大部分收集工做都是和應用併發進行的,在進行收集的時候,應用的暫停時間很短。若是綜合使用-XX:+UseParNewGC和-XX:+UseConcMarkSweepGC,那麼在新生代上使用並行的收集策略。

             3. 增量收集器(incremental low pause collector):命令行參數:-Xincgc。使用增量收集器要謹慎,他只是在每次進行次要收集的時候對舊生代進行一部分的收集,這樣就把主要收集所帶來的較長時間的停頓分散到屢次的次要收集。可是,考慮到總共的吞吐,可能比舊生代上默認的收集還要慢。

    注意,-XX:+UseParallelGC和XX:+UseConcMarkSweepGC不能同時使用。對於J2SE1.4.2版本會檢查垃圾收集相關參數組合的合法性,可是對於以前的版本沒有這個檢查,可能會致使不可預知的錯誤。

    垃圾回收器相關參數

    串行垃圾收集器參數

     

參數

說明

-XX:+UseSerialGC

設置串行收集器。

 

 

 

10.2.  並行垃圾收集器參數

參數

說明

-XX:+UseParallelGC

選擇垃圾收集器爲並行收集器,此配置僅對年輕代有效,即上述配置下,年輕代使用並行收集,而老年代仍舊使用串行收集。採用了多線程並行管理和回收垃圾對象,提升了回收效率,提升了服務器的吞吐量,適合於多處理器的服務器。

-XX:ParallelGCThreads

配置並行收集器的線程數,即:同時多少個線程一塊兒進行垃圾回收。此值最好配置與處理器數目相等。

-XX:+UseParallelOldGC

採用對於老年代併發收集的策略,能夠提升收集效率。JDK6.0支持對老年代並行收集。

-XX:MaxGCPauseMillis

設置每次年輕代並行收集最大暫停時間,若是沒法知足此時間,JVM會自動調全年輕代大小以知足此值。

-XX:+UseAdaptiveSizePolicy

設置此選項後,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低響應時間或者收集頻率等,此值建議使用並行收集器時,一直打開。

-XX:+UseParNewGC

指定在 New Generation使用 parallel collector,是 UseParallelGC的 gc的升級版本 ,有更好的性能或者優勢 ,能夠和 CMS gc一塊兒使用

 

10.3.  併發垃圾收集器參數

參數

說明

-XX:+UseConcMarkSweepGC

指定在老年代使用 concurrent cmark sweep gc。gc thread和 app thread並行 (在 init-mark和 remark時 pause app thread)。app pause時間較短 ,適合交互性強的系統 ,如 web server。它能夠併發執行收集操做,下降應用中止時間,同時它也是並行處理模式,能夠有效地利用多處理器的系統的多進程處理。

-XX:+UseCMSCompactAtFullCollection

打開對老年代的壓縮。可能會影響性能,可是能夠消除碎片,在FULL GC的時候,壓縮內存, CMS是不會移動內存的,所以,這個很是容易產生碎片,致使內存不夠用,所以,內存的壓縮這個時候就會被啓用。增長這個參數是個好習慣。

-XX:+CMSIncrementalMode

設置爲增量模式。適用於單CPU狀況

-XX:CMSFullGCsBeforeCompaction

因爲併發收集器不對內存空間進行壓縮、整理,因此運行一段時間之後會產生「碎片」,使得運行效率下降。此值設置運行多少次GC之後對內存空間進行壓縮、整理。

-XX:+CMSClassUnloadingEnabled

使CMS收集持久代的類,而不是fullgc

-XX:+CMSPermGenSweepingEnabled

使CMS收集持久代的類,而不是fullgc。

-XX:-CMSParallelRemarkEnabled

在使用 UseParNewGC的狀況下 ,儘可能減小 mark的時間。

-XX:CMSInitiatingOccupancyFraction

說明老年代到百分之多少滿的時候開始執行對老年代的併發垃圾回收(CMS),這個參數設置有很大技巧,基本上知足公式:

(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn

時就不會出現promotion failed。在個人應用中Xmx是6000,Xmn是500,那麼Xmx-Xmn是5500兆,也就是老年代有5500兆,CMSInitiatingOccupancyFraction=90說明老年代到90%滿的時候開始執行對老年代的併發垃圾回收(CMS),這時還剩10%的空間是5500*10%=550兆,因此即便Xmn(也就是年輕代共500兆)裏全部對象都搬到老年代裏,550兆的空間也足夠了,因此只要知足上面的公式,就不會出現垃圾回收時的promotion failed;

若是按照Xmx=2048,Xmn=768的比例計算,則CMSInitiatingOccupancyFraction的值不能超過40,不然就容易出現垃圾回收時的promotion failed。

-XX:+UseCMSInitiatingOccupancyOnly

指示只有在老年代在使用了初始化的比例後 concurrent collector 啓動收集

11.   JVM內存溢出類型

對於JVM的內存寫過的文章已經有點多了,並且有點爛了,不過說那麼多大多數在解決OOM的狀況,於此,本文就只闡述這個內容,攜帶一些分析和理解和部分擴展內容,也就是JVM宕機中的一些問題,OK,下面說下OOM的常見狀況:

第一類內存溢出,就是堆棧溢出:關鍵字:java.lang.OutOfMemoryError: ......javaheap space.....

也就是當你看到heap相關的時候就確定是堆棧溢出了,此時若是代碼沒有問題的狀況下,適當調整-Xmx和-Xms是能夠避免的,不過必定是代碼沒有問題的前提,爲何會溢出呢,要麼代碼有問題,要麼訪問量太多而且每一個訪問的時間太長或者數據太多,致使數據釋放不掉,由於垃圾回收器是要找到那些是垃圾才能回收,這裏它不會認爲這些東西是垃圾,天然不會去回收了;主意這個溢出以前,可能系統會提早先報錯關鍵字爲:

java.lang.OutOfMemoryError:GC over headlimit exceeded

這種狀況是當系統處於高頻的GC狀態,並且回收的效果依然不佳的狀況,就會開始報這個錯誤,這種狀況通常是產生了不少不能夠被釋放的對象,有多是引用使用不當致使,或申請大對象致使,可是java heap space的內存溢出有可能提早不會報這個錯誤,也就是可能內存就直接不夠致使,而不是高頻GC.

 

第二類內存溢出,PermGen的溢出,或者PermGen滿了的提示,你會看到這樣的關鍵字:關鍵信息爲:java.lang.OutOfMemoryError: PermGenspace

緣由:系統的代碼很是多或引用的第三方包很是多、或代碼中使用了大量的常量、或經過intern注入常量、或者經過動態代碼加載等方法,致使常量池的膨脹,雖然JDK 1.5之後能夠經過設置對永久帶進行回收,可是咱們但願的是這個地方是不作GC的,它夠用就行,因此通常狀況下今年少作相似的操做,因此在面對這種狀況經常使用的手段是:增長-XX:PermSize和-XX:MaxPermSize的大小。

 

第三類內存溢出:在使用ByteBuffer中的allocateDirect()的時候會用到,不少javaNIO的框架中被封裝爲其餘的方法溢出關鍵字:java.lang.OutOfMemoryError: Directbuffer memory

若是你在直接或間接使用了ByteBuffer中的allocateDirect方法的時候,而不作clear的時候就會出現相似的問題,常規的引用程序IO輸出存在一個內核態與用戶態的轉換過程,也就是對應直接內存與非直接內存,若是常規的應用程序你要將一個文件的內容輸出到客戶端須要經過OS的直接內存轉換拷貝到程序的非直接內存(也就是heap中),而後再輸出到直接內存由操做系統發送出去,而直接內存就是由OS和應用程序共同管理的,而非直接內存能夠直接由應用程序本身控制的內存,jvm垃圾回收不會回收掉直接內存這部分的內存,因此要注意了哦。

若是常常有相似的操做,能夠考慮設置參數:-XX:MaxDirectMemorySize

 

第四類內存溢出錯誤:溢出關鍵字:java.lang.StackOverflowError

這個參數直接說明一個內容,就是-Xss過小了,咱們申請不少局部調用的棧針等內容是存放在用戶當前所持有的線程中的,線程在jdk 1.4之前默認是256K,1.5之後是1M,若是報這個錯,只能說明-Xss設置得過小,固然有些廠商的JVM不是這個參數,本文僅僅針對Hotspot VM而已;不過在有必要的狀況下能夠對系統作一些優化,使得-Xss的值是可用的。

 

第五類內存溢出錯誤:溢出關鍵字:java.lang.OutOfMemoryError: unable tocreate new native thread

上面第四種溢出錯誤,已經說明了線程的內存空間,其實線程基本只佔用heap之外的內存區域,也就是這個錯誤說明除了heap之外的區域,沒法爲線程分配一塊內存區域了,這個要麼是內存自己就不夠,要麼heap的空間設置得太大了,致使了剩餘的內存已經很少了,而因爲線程自己要佔用內存,因此就不夠用了,說明了緣由,如何去修改,不用我多說,你懂的。

 

第六類內存溢出:溢出關鍵字java.lang.OutOfMemoryError: request {}byte for {}out of swap

這類錯誤通常是因爲地址空間不夠而致使。

六大類常見溢出已經說明JVM中99%的溢出狀況,要逃出這些溢出狀況很是困難,除非一些很怪異的故障問題會發生,好比因爲物理內存的硬件問題,致使了code cache的錯誤(在由byte code轉換爲native code的過程當中出現,可是機率極低),這種狀況內存會被直接crash掉,相似還有swap的頻繁交互在部分系統中會致使系統直接被crash掉,OS地址空間不夠的話,系統根本沒法啓動,呵呵;JNI的濫用也會致使一些本地內存沒法釋放的問題,因此儘可能避開JNI;socket鏈接數據打開過多的socket也會報相似:IOException: Too many open files等錯誤信息。

JNI就不用多說了,儘可能少用,除非你的代碼太牛B了,我無話可說,呵呵,這種內存若是沒有在被調用的語言內部將內存釋放掉(如C語言),那麼在進程結束前這些內存永遠釋放不掉,解決辦法只有一個就是將進程kill掉。

另外GC自己是須要內存空間的,由於在運算和中間數據轉換過程當中都須要有內存,因此你要保證GC的時候有足夠的內存哦,若是沒有的話GC的過程將會很是的緩慢。

 

12.   JAVA虛擬機參數分類說明

12.1.  標準參數(-)

所謂的Java虛擬機標準參數指的就是全部的虛擬機實現都應該支持的參數,這部分參數基本上都是對虛擬機基本能力的調整,包括對運行模式、垃圾收集信息顯示、顯示版本信息、斷言開關等,下面是以Solaris下1.4.2版本爲例:

參數

使用說明

備註

-d32

-d64

指明該Java VM是運行與32位環境仍是64位環境,默認是運行在32位環境下的,若是是配置了64位模式則須要操做系統也必須是64位的,固然CPU更須要是64位的。另外若是咱們選擇了-server參數,則就暗含了64位模式。

由於64的CPU兼容32位操做系統,而64位操做系統又是兼容32位執行程序

-client

-server

設置該JVM運行與Client或者Server Hotspot模式,這兩種模式從本質上來講是在JVM中運行不一樣的JIT(運行時編譯模塊)代碼,而且二者在JVM內部的接口是一致的。客戶端模式優化的是系統啓動時間更快,而服務端模式的優化則更關注與系統的總體性能。通常來講Client選項用於GUI的應用,Server選項多用於後臺服務器應用。

另外二者在編譯策略、垃圾收集策略、堆使用上也有所不一樣

-hotspot

在Hotspot類型的JVM中缺省使用,缺省爲Client Hotspot模式。

 

-cp

-classpath

指明JVM啓動時要加載的類文件路徑,Java虛擬機進程在啓動時就會按照該參數後面指明的路徑查找*.zip、*.jar、*.class文件,而後將這些包中的類文件加載到內存中。

JVM加載類文件的順序是

-D<name>=<value>

設置系統屬性的值,該參數是的設計是爲了知足Java應用程序員與JVM進行參數傳遞的手段之一,另外一種是經過應用級參數(argument)來實現。

Java程序員能夠在程序內調用system.getProperty來獲取用戶經過-D參數傳進來的系統屬性信息。而命令行參數就是是JVM傳遞給main函數的調用參數

 

-verbose:class

 

-verbose:gc

 

-verbose:jni

打印詳細信息,目前支持打印類加載信息:class、垃圾收集信息:gc、以及本地方法調用信息:jni,若是選擇了此選項,則JVM會在命令行打印出上述信息;

對於測試中的系統能夠經過打開:gc開關,查看JVM每次垃圾收集的詳細信息來判斷系統內存消耗狀況,若是系統垃圾收集的很頻繁,並且每次都回收了大量的內存,則說明系統內存消耗很大,對象的建立和湮滅很頻繁,而若是堆內存一直保持着增加的話,說明可能存在內存「泄漏」。

-version

-showversion

-version選項是顯示版本信息後JVM退出

-showversion選項是顯示版本信息後JVM繼續運行

 

-esa

-enableassertions

打開系統中每一個類的斷言開關

該選項用於程序開發、調試過程

-da

-disableassertions

關閉系統中每一個類的斷言開關

該選項用於程序開發、調試過程

 

 

 

 

                  1. JVM標準參數集

 

12.2.  擴展參數(-X)

 

所謂的Java虛擬機非標準參數指的就是一些特有的虛擬機實現所支持,下面以Solaris下1.4.2版本爲例介紹一些擴展的虛擬機運行參數,其中對Hotspot VM相關的參數是咱們進行性能調整的重點。

 

參數

使用說明

備註

-Xmixed

JVM執行模式的設置參數,混合模式即支持Hotspot即時編譯的運行模式

支持Hotspot的JVM缺省都是運行於混合模式的。

-Xint

設置JVM的執行模式爲解釋執行模式,純解釋執行的JVM對多數應用來講基本上時沒有意義的,僅僅可能會在一些嵌入式系統中應用

 

-Xbootclasspath

設置初始類裝載器的裝載路徑

 

-Xnoclassgc

設置不執行類垃圾收集

 

-Xincgc

設置是否啓動火車垃圾收集算法

 

-Xloggc:<file>

設置是否將GC信息寫入日誌文件

 

-Xbatch

設置不執行後臺編譯

 

-Xms<size>

設置JVM啓動時初始內存堆的大小

 

-Xmx<size>

設置JVM啓動後動態申請堆內存的最大堆空間

 

-Xss<size>

設置JVM最大線程棧的空間大小

 

-Xprof

是否打印輸出性能統計數據

 

-Xrunhprof

設置是否啓動heap、cpu等性能統計監控功能(詳細見下表)

 

-Xdebug

設置是否啓動遠程調試功能

 

-Xfuture

 

 

-Xrs

設置是否屏蔽操做系統信號

 

-Xcheck:jni

設置對於本地調用是否執行額外檢查

 

 

                  1. JVM擴展參數集

Java Hotspot、GC相關參數介紹,下面以Solaris下1.4.2版本爲例,對於以–X打頭的非標準參數,是不能保證在每一個JVM的實現中都支持的,並且關於這些參數行爲的改變都不會獲得通知。

 

12.3.  非穩定(Stable)參數(-XX)

而對於以–XX打頭的非標準參數來講,它們中大多數都是和具體的操做系統支持有關的,並且有些甚至須要特殊的系統訪問權限,並且這些參數也是遵循上述的改變不通知原則的。在使用中須要特別注意。

在Sun的文檔中,又分爲三類:

行爲參數(Behavioral Options):用於改變jvm的一些基礎行爲;
性能調優(Performance Tuning):用於jvm的性能調優;
調試參數(Debugging Options):通常用於打開跟蹤、打印、輸出等jvm參數,用於顯示jvm更加詳細的信息;

 

12.3.1. 行爲參數

參數及其默認值

描述

-XX:-DisableExplicitGC

禁止調用System.gc();但jvm的gc仍然有效

-XX:+MaxFDLimit

最大化文件描述符的數量限制

-XX:+ScavengeBeforeFullGC

新生代GC優先於Full GC執行

-XX:+UseGCOverheadLimit

在拋出OOM以前限制jvm耗費在GC上的時間比例

-XX:-UseConcMarkSweepGC

對老生代採用併發標記交換算法進行GC

-XX:-UseParallelGC

啓用並行GC

-XX:-UseParallelOldGC

對Full GC啓用並行,當-XX:-UseParallelGC啓用時該項自動啓用

-XX:-UseSerialGC

啓用串行GC

-XX:+UseThreadPriorities

啓用本地線程優先級

 

上面表格中黑體的三個參數表明着jvm中GC執行的三種方式,即串行、並行、併發;

串行(SerialGC是jvm的默認GC方式,通常適用於小型應用和單處理器,算法比較簡單,GC效率也較高,但可能會給應用帶來停頓;

並行(ParallelGC是指GC運行時,對應用程序運行沒有影響,GC和app二者的線程在並行執行,這樣能夠最大限度不影響app的運行;

併發(ConcMarkSweepGC是指多個線程併發執行GC,通常適用於多處理器系統中,能夠提升GC的效率,但算法複雜,系統消耗較大;

 

12.3.2. 性能調優

參數及其默認值

描述

-XX:LargePageSizeInBytes=4m

設置用於Java堆的大頁面尺寸

-XX:MaxHeapFreeRatio=70

GC後java堆中空閒量佔的最大比例

-XX:MaxNewSize=size

新生成對象能佔用內存的最大值

-XX:MaxPermSize=64m

老生代對象能佔用內存的最大值

-XX:MinHeapFreeRatio=40

GC後java堆中空閒量佔的最小比例

-XX:NewRatio=2

新生代內存容量與老生代內存容量的比例

-XX:NewSize=2.125m

新生代對象生成時佔用內存的默認值

-XX:ReservedCodeCacheSize=32m

保留代碼佔用的內存容量

-XX:ThreadStackSize=512

設置線程棧大小,若爲0則使用系統默認值

-XX:+UseLargePages

使用大頁面內存

 

12.3.3. 調試/打印信息參數

參數及其默認值

描述

-XX:-CITime

打印消耗在JIT編譯的時間

-XX:ErrorFile=./hs_err_pid<pid>.log

保存錯誤日誌或者數據到文件中

-XX:-ExtendedDTraceProbes

開啓solaris特有的dtrace探針

-XX:HeapDumpPath=./java_pid<pid>.hprof

指定導出堆信息時的路徑或文件名

-XX:HeapDumpOnOutOfMemoryError

當首次遭遇OOM時導出此時堆中相關信息

-XX:OnError="<cmd args>;<cmd args>"

出現致命ERROR以後運行自定義命令

-XX:OnOutOfMemoryError="<cmd args>;<cmd args>"

當首次遭遇OOM時執行自定義命令

-XX:-PrintClassHistogram

遇到Ctrl-Break後打印類實例的柱狀信息,與jmap -histo功能相同

-XX:-PrintConcurrentLocks

遇到Ctrl-Break後打印併發鎖的相關信息,與jstack -l功能相同

-XX:-PrintCommandLineFlags

打印在命令行中出現過的標記

-XX:-PrintCompilation

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

-XX:-PrintGC

每次GC時打印相關信息

-XX:-PrintGC Details

每次GC時打印詳細信息

-XX:-PrintGCTimeStamps

打印每次GC的時間戳

-XX:-TraceClassLoading

跟蹤類的加載信息

-XX:-TraceClassLoadingPreorder

跟蹤被引用到的全部類的加載信息

-XX:-TraceClassResolution

跟蹤常量池

-XX:-TraceClassUnloading

跟蹤類的卸載信息

-XX:-TraceLoaderConstraints

跟蹤類加載器約束的相關信息

 

12.3.4. 參數彙總(不含調試和垃圾收集參數)

參數

使用說明

備註

-XX:+AggressiveHeap

長時間大內存使用的優化,能檢查計算資源(內存,處理器數量),至少須要256MB內存,大量的CPU/內存,(在1.4.1在4CPU的機器上已經顯示有提高)

 

-XX:+AggressiveOpts

加快編譯

 

-XX:-AllowUserSignal

Handlers

容許用戶在應用層設置信號處理回調函數

 

-XX:AltStackSize=16384

預備信號棧的大小

 

-XX:-CITime

設置Hotspot的一次即時編譯所須要的最大時間

 

-XX:CompileThreshold

=10000

設置方法是否進行即時編譯的調用次數的下限值,-server選項的缺省值爲10000,-client選項的缺省值爲1500

即:當該方法的被調用測試多於該值時,則該方法就會被JIT即時編譯器編譯成機器代碼在內存中執行

-XX:+DisableExplicitGC

屏蔽程序主動垃圾收集的函數system.gc()

 

-XX:FreqInlineSize=size

限制常用的動態編譯的函數的虛擬機指令的最大數量,

 

-Xincgc

在垃圾收集中使用火車算法

 

-Xint

不啓用即時編譯(JIT)功能,僅僅解釋執行

缺省爲不選的

-XX:LargePageSizeInBytes

內存頁的大小,不可設置過大,會影響Perm的大小。

 

 

 

 

-XX:MaxHeapFreeRatio

=<Maximum>

JVM中堆空間的最大空閒百分比,缺省爲70%,GC中止回收空間的上限值

即:一旦當前堆內存空閒空間百分比超過總空間70%時,GC暫停垃圾收集

-XX:MinHeapFreeRatio

=<Minimum>

JVM中堆空間的最小空閒百分比,缺省爲40%,GC開始回收空間的下限值

即:一旦當前內存堆中內存空閒小於40%時,GC則恢復垃圾收集

-XX:MaxInlineSize=size

限制動態編譯的內聯函數的虛擬機指令的最大數量

 

-XX:+MaxFDLimit

設置JVM進程打開最大文件句柄數(Solaris only)

 

-XX:MaxNewSize=32m

在爲新生代對象分配內存值,每塊內存的最大值。

按代垃圾收集中使用

-XX:MaxTenuringThreshold=30

在存活區之間Copy的次數,超過該次數則移至Old區。

 

-Xmn

爲新生代分配的內存大小。

 

-XX:NewRatio=2

新生代與老一代空間的比率,-XX:NewRatio = 2表示 Eden:old = 1:2。SUN Parc –server中是2:1,Intel中是12:1。

 

-XX:NewSize=2228224

新一代的缺省申請空間的值

對於大型應用服務器系統這個值2K通常狀況下須要調整大一些

-Xnoincgc

在垃圾收集中不使用火車算法

 

-XX:PreBlockSpin=10

 

 

-XX:-PrintTenuring

Distribution

打印使用年限

 

-XX:ReservedCodeCache

Size=32m

設置內存中保留代碼緩衝區的大小

 

-XX:SoftRefLRUPolicyMSPerMB

相對於客戶端模式的虛擬機(-client選項),當使用服務器模式的虛擬機時(-server選項),對於軟引用(soft reference)的清理力度要稍微差一些。能夠經過增大-XX:SoftRefLRUPolicyMSPerMB來下降收集頻率。默認值是 1000,也就是說每秒一兆字節。Soft reference在虛擬機中比在客戶集中存活的更長一些。其清除頻率能夠用命令行參數-XX:SoftRefLRUPolicyMSPerMB=<N>來控制,這能夠指定每兆堆空閒空間的 soft reference保持存活(一旦它不強可達了)的毫秒數,這意味着每兆堆中的空閒空間中的 soft reference會(在最後一個強引用被回收以後)存活1秒鐘。注意,這是一個近似的值,由於 soft reference只會在垃圾回收時纔會被清除,而垃圾回收並不總在發生。

 

-XX:SurvivorRatio=64

存活區和eden區所佔的比率:2:64

 

-XX:TargetSurvivorRatio

=50

該值是一個百分比,控制容許使用的生存區空間的比例,默認值是50。即佔到50%,則執行Copy策略。該參數設置較大的話可提升對survivor空間的使用率。

 

-XX:ThreadStackSize

=512

每一個線程棧大小(K),等於0時表示使用缺省值【Sparc: 512K,Solaris Intel: 256K,Sparc 64bit: 1024其餘的都爲0】

 

-XX:+UseBoundThreads

綁定用戶級線程(Solaris only),這個選項強制全部的Java線程在建立時都做爲操做系統綁定的線程

這個參數用來是否將JVM用戶線程綁定到Solaris內核線程

-XX:+UseAltSigs

 

 

-XX:+UseV8InstrsOnly

 

 

-XX:-UseLWPSynchroniza

tion

使用操做系統提供的輕量級線程LWP同步來代替基於Java虛擬機的線程的同步

該參數的使用使得JVM將線程同步的控制交由Solaris內核處理,從而代替了JVM內部的線程同步機制

-XX:+UseThreadPriorities

設置是否使用本地線程優先級

 

-XX:-UseSpinning

 

 

-XX:+UseTLAB

是否使用線程本地對象分配策略,SUN Sparc –server時爲true,其餘爲false

 

-XX:-UseISM

若是使用ISM選項能夠得到以下的幾個好處:一、使用大內存頁來代替操做系統缺省的8K的頁模式;

二、將一些內存頁鎖定在內存中,而沒必要換出到硬盤

 

若是系統使用ISM則系統文件/etc/system須要添加以下配置:

set shmsys:

shminfo_shmmax

=0xffffffff

set shmsys:

shminfo_shmseg=32

-XX:+UseFastAccessorMethods

原始類型的快速優化,get,set方法轉成本地代碼。

 

-XX:+UseBiasedLocking

鎖機制的性能改善。

 

 

                  1. JVM GC/Hotspot相關參數集

 

注:即時編譯是Hotspot中的概念,按代收集,火車算法等是屬於GC中的概念。

 

13.   項目調優經驗1

  1. CMS垃圾收集器

    Date:2010-12-24

    JVM參數:

 

-Xss2M -XX:PermSize=128M -XX:MaxPermSize=128M -Xms2G -Xmx2G -Xmn832M -XX:SurvivorRatio=6 -XX:TargetSurvivorRatio=80 -XX:ParallelGCThreads=8 -XX:+UseConcMarkSweepGC

 

觀察分析:

  1. 新生代每次執行一次垃圾收集,舊生代增長一點:

舊生代:489,711 Kbà489,740Kb ;

新生代(638,976kb):651,878Kbà29,00kb

存活區(106,496kb):約10,000kbà5,000kb

上述數聽說明:對象在存活只存活一個週期,就被移到舊生代;相對應新生代每次收集存活區的最高利用率只有10%,根據上述參數能夠把存活區Copy次數改成:(新生代分配值/存活區最大利用值)*目標存活區利用率=(100M/10M)*80%=8次

 

  1. 垃圾收集數據

    新生代收集:ParNew29388次,用時:13m

    舊生代:ConurrentMarkSweep:0次,用時0s

     

    新生代平均每次收集暫停時間爲:0.027s(平均每次用時:13m/29388=0.027s)。

    新生代收集29388次,舊生代0次:舊生代內存利用率遠遠低於新生代,能夠適當放大舊生代,縮小新生代。

     

  2.  

     

    結論:擴大新生代內存,縮小舊生代內存,相應提高併發收集線程數量;增長-XX:MaxTenuringThreshold參數,設置值爲8,要求對象在存活區之間Copy 10次在移動到舊生代。

     

 

  1. 並行垃圾收集自適應調整堆內存

     

**管控項目:64位windows服務器

jvm 64位: jdk1.5.0_16_b02

上線時間:2010.10,出現jvm不響應時間:2010.12.16

 

啓動參數:

-server-Xss2M -XX:PermSize=64M -XX:MaxPermSize=64M

-XX:+UseParallelGC-XX:+UseAdaptiveSizePolicy -XX:+AggressiveHeap -XX:ParallelGCThreads=4

說明:採用並行垃圾回收器,堆內存經過JVM自適應調整(-XX:+UseAdaptiveSizePolicy-XX:+AggressiveHeap)。

 

問題:2010.12.16項目組發現運行在jvm上的引擎服務不響應,經分析是jvm在作垃圾全收集時,對jvm進行了一次自動重啓。

方案:採用」併發收集器,內存參數固定」,手動執行垃圾收集後,不出現jvm重啓現象。

 

  1. 採用併發收集,內存固定

**管控項目:64位windows服務器

jvm 64位: jdk1.5.0_16_b02

啓動參數:

-server-Xss2M -XX:PermSize=64M -XX:MaxPermSize=64M -Xms2G -Xmx2G -Xmn512M

-XX:SurvivorRatio=16-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=10 -XX:ParallelGCThreads=4

 

分析:舊生代採用併發垃圾收集器(CMS)管理;新生代採用並行垃圾收集器(Parall);內存參數固定。

正常運行時間: 

1 hour 4 minutes

處理 CPU時間: 

6 minutes

JIT編譯器: 

HotSpot 64-Bit Server Compiler

編譯總時間: 

1 minute

 

垃圾收集器: 

Name = 'ParNew', Collections = 158, Total time spent = 9.392秒

垃圾收集器: 

Name = 'ConcurrentMarkSweep', Collections = 1, Total time spent = 2.076秒

 

14.   調優經驗(摘抄)

 

14.1.  GC調優參數的使用

JVM中按代收集算法的基本原則是這樣的,JVM堆空間被分紅許多子堆,每一個子堆用於存放不一樣代的對象,而當全部已經存在的堆中的各代對象都不能繼續回收時,則新的子堆會被分配,用於存放新一代的對象,下面的這兩個參數就是爲按代收集設計的:

 

-XX:NewRatio=2              //新生代於老一代的空間比率

-XX:NewSize=2228224           //缺省時2K,對於應用服務器系統建議調整的大一些4K或8K

-XX:MaxNewSize                    //新生代的最大空間

-XX:MaxPermSize=64m         //老一代的最大空間,缺省爲64M,建議增長

-XX:SurvivorRatio                  //GC時代子堆中的年老對象的比率

-Xxincgc                           //是否在垃圾收集時啓用火車算法

-XX:+UseConcMarkSweepGC//是否啓用併發收集算法

-Xverifyheap              //僅僅用於Debug版本,用於對GC數據分析

-XX:TargetSurvivorRatio=50   //GC收集後指望獲得的被老一代佔用的空間,建議不調整

 

由於垃圾收集只是在各代的子堆滿了的時候發生,總的堆的空間情況也會對垃圾收集產生重要的影響,JVM向操做系統申請更多的堆內存空間的前提是,堆中全部的年老的代的子堆都已經滿了。

-Xms                          //設置最小初始堆空間的大小

-Xmx                          //設置最大堆空間的大小

-XX:MinFreeHeapRatio=40     //GC後JVM堆空間向操做系統縮小的比率。

-XX:MaxHeapFreeRatio=70  //GC後JVM堆空間向操做系統擴張的比率。

-XX:+AggressiveHeap            //用於JVM運行於大內存模式下,JVM的堆空間至少在1G以上,與-Xms、-Xmx不一樣時使用,慎用!會致使JVM極度消/耗內存

 

在U-NICA這樣的後臺大型應用服務器系統來講,咱們就採用了經過調整初始堆內存空間、堆增加量、增長新生代空間配置、使用併發收集算法、火車算法等方法來使的系統的垃圾收集能力得以優化。並且在具體實際測試過程當中也發現這些調整一般是有效並且成本低廉的。

 

14.2.  JIT調優參數的使用

從解釋執行到即時編譯,再到熱點編譯JVM走在一條不斷優化的道路上,今天咱們經過一些簡單的參數設置就能夠得到之前夢想的性能,對於Java用戶來講,這的確是一條捷徑:

-server                       //不少Hotspot的能力都是經過這個選項打開的,對於大型服務器尤其重要,這裏能夠啓動熱點編譯功能

-Xmaxjitcodesize32m       //設置即時編譯代碼的最大尺寸

-Xint                           //純解釋執行,通常狀況下不用它

-Xtime                        //不太清楚如何使用,總之是指定JIT的時間

-XX:+DisableExplicitGC          //是否屏蔽應用層的垃圾收集請求

-XX:-UseISM                    //使用大內存頁模式則會減小GC的時間

-XX:-UseMPSS                //在使用ISM選項的同時不使用該選項,不然ISM無效

14.3.  Java線程調優參數的使用

-XX:-UseBoundThreads          //若是你的系統是Solaris8以上,盡情使用這個參數吧,操做系統內核的線程調度老是要必應用層的調度快一些

-XX:-UseLWPSynchronization//這個參數也是一樣的,讓操做系統來作線程同步這些工做

-XX:+UseThreadPriorities       //是否採用操做系統內部定義的線程優先級

-XX:CompileThreshold=10000//若是你想讓你的系統更早變快一些,並且你的內存足夠多的話,能夠將這個參數值調小

-XX:PreBlockSpin=10             //僅僅用於Linux版本

-XX:ThreadStackSize=512     //設置線程棧的大小,若是你的應用中有比較大的循環或遞歸時使用。

-XX:+UseTLAB                //是否在線程的棧空間內分配對象,若是你的內存較大的話,而且配置了比較大的線程棧空間,則使用這個參數會使得臨時&本地對象的申請和釋放比較快。

相關文章
相關標籤/搜索