JVM調優

jopen 10年前發布 | 24K 次閱讀 JVM Java開發

數據類型

    Java虛擬機中,數據類型可以分為兩類:基本類型引用類型。基本類型的變量保存原始值,即:他代表的值就是數值本身;而引用類型的變量保存引用值。“引用值”代表了某個對象的引用,而不是對象本身,對象本身存放在這個引用值所表示的地址的位置。

基本類型包括:byte,short,int,long,char,float,double,Boolean,returnAddress

引用類型包括:類類型接口類型數組

堆與棧

    堆和棧是程序運行的關鍵,很有必要把他們的關系說清楚。

棧是運行時的單位,而堆是存儲的單位

    棧解決程序的運行問題,即程序如何執行,或者說如何處理數據;堆解決的是數據存儲的問題,即數據怎么放、放在哪兒。

    在Java中一個線程就會相應有一個線程棧與之對應,這點很容易理解,因為不同的線程執行邏輯有所不同,因此需要一個獨立的線程棧。而堆則是所有線程共享的。棧因為是運行單位,因此里面存儲的信息都是跟當前線程(或程序)相關信息的。包括局部變量、程序運行狀態、方法返回值等等;而堆只負責存儲對象信息。

為什么要把堆和棧區分出來呢?棧中不是也可以存儲數據嗎

    第一,從軟件設計的角度看,棧代表了處理邏輯,而堆代表了數據。這樣分開,使得處理邏輯更為清晰。分而治之的思想。這種隔離、模塊化的思想在軟件設計的方方面面都有體現。

    第二,堆與棧的分離,使得堆中的內容可以被多個棧共享(也可以理解為多個線程訪問同一個對象)。這種共享的收益是很多的。一方面這種共享提供了一種有效的數據交互方式(如:共享內存),另一方面,堆中的共享常量和緩存可以被所有棧訪問,節省了空間。

    第三,棧因為運行時的需要,比如保存系統運行的上下文,需要進行地址段的劃分。由于棧只能向上增長,因此就會限制住棧存儲內容的能力。而堆不同,堆中的對象是可以根據需要動態增長的,因此棧和堆的拆分,使得動態增長成為可能,相應棧中只需記錄堆中的一個地址即可。

    第四,面向對象就是堆和棧的完美結合。其實,面向對象方式的程序與以前結構化的程序在執行上沒有任何區別。但是,面向對象的引入,使得對待問題的思考方式發生了改變,而更接近于自然方式的思考。當我們把對象拆開,你會發現,對象的屬性其實就是數據,存放在堆中;而對象的行為(方法),就是運行邏輯,放在棧中。我們在編寫對象的時候,其實即編寫了數據結構,也編寫的處理數據的邏輯。不得不承認,面向對象的設計,確實很美。

在Java中,Main函數就是棧的起始點,也是程序的起始點

    程序要運行總是有一個起點的。同C語言一樣,java中的Main就是那個起點。無論什么java程序,找到main就找到了程序執行的入口:)

堆中存什么?棧中存什么

    堆中存的是對象。棧中存的是基本數據類型和堆中對象的引用。一個對象的大小是不可估計的,或者說是可以動態變化的,但是在棧中,一個對象只對應了一個4btye的引用(堆棧分離的好處:))。

    為什么不把基本類型放堆中呢?因為其占用的空間一般是1~8個字節——需要空間比較少,而且因為是基本類型,所以不會出現動態增長的情況——長度固定,因此棧中存儲就夠了,如果把他存在堆中是沒有什么意義的(還會浪費空間,后面說明)。可以這么說,基本類型和對象的引用都是存放在棧中,而且都是幾個字節的一個數,因此在程序運行時,他們的處理方式是統一的。但是基本類型、對象引用和對象本身就有所區別了,因為一個是棧中的數據一個是堆中的數據。最常見的一個問題就是,Java中參數傳遞時的問題。

Java中的參數傳遞時傳值呢?還是傳引用

    要說明這個問題,先要明確兩點:

         1. 不要試圖與C進行類比,Java中沒有指針的概念

         2. 程序運行永遠都是在棧中進行的,因而參數傳遞時,只存在傳遞基本類型和對象引用的問題。不會直接傳對象本身。

    明確以上兩點后。Java在方法調用傳遞參數時,因為沒有指針,所以它都是進行傳值調用(這點可以參考C的傳值調用)。因此,很多書里面都說Java是進行傳值調用,這點沒有問題,而且也簡化的C中復雜性。

但是傳引用的錯覺是如何造成的呢?在運行棧中,基本類型和引用的處理是一樣的,都是傳值,所以,如果是傳引用的方法調用,也同時可以理解為“傳引用值”的傳值調用,即引用的處理跟基本類型是完全一樣的。但是當進入被調用方法時,被傳遞的這個引用的值,被程序解釋(或者查找)到堆中的對象,這個時候才對應到真正的對象。如果此時進行修改,修改的是引用對應的對象,而不是引用本身,即:修改的是堆中的數據。所以這個修改是可以保持的了。

    對象,從某種意義上說,是由基本類型組成的。可以把一個對象看作為一棵樹,對象的屬性如果還是對象,則還是一顆樹(即非葉子節點),基本類型則為樹的葉子節點。程序參數傳遞時,被傳遞的值本身都是不能進行修改的,但是,如果這個值是一個非葉子節點(即一個對象引用),則可以修改這個節點下面的所有內容。

    堆和棧中,棧是程序運行最根本的東西。程序運行可以沒有堆,但是不能沒有棧。而堆是為棧進行數據存儲服務,說白了堆就是一塊共享的內存。不過,正是因為堆和棧的分離的思想,才使得Java的垃圾回收成為可能。

     Java中,棧的大小通過-Xss來設置,當棧中存儲數據比較多時,需要適當調大這個值,否則會出現java.lang.StackOverflowError異常。常見的出現這個異常的是無法返回的遞歸,因為此時棧中保存的信息都是方法返回的記錄點。

按照基本回收策略分

引用計數(Reference Counting):

比較古老的回收算法。原理是此對象有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只用收集計數為0的對象。此算法最致命的是無法處理循環引用的問題。

標記-清除(Mark-Sweep):

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

復制(Copying):

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

標記-整理(Mark-Compact):

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

按分區對待的方式分

增量收集(Incremental Collecting):實時垃圾回收算法,即:在應用進行的同時進行垃圾回收。不知道什么原因JDK5.0中的收集器沒有使用這種算法的。

分代收集(Generational Collecting):基于對對象生命周期分析后得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命周期的對象使用不同的算法(上述方式中的一個)進行回收。現在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。

按系統線程分

串行收集:串行收集使用單線程處理所有垃圾回收工作,因為無需多線程交互,實現容易,而且效率比較高。但是,其局限性也比較明顯,即無法使用多處理器的優勢,所以此收集適合單處理器機器。當然,此收集器也可以用在小數據量(100M左右)情況下的多處理器機器上。

并行收集:并行收集使用多線程處理垃圾回收工作,因而速度快,效率高。而且理論上CPU數目越多,越能體現出并行收集器的優勢。

并發收集:相對于串行收集和并行收集而言,前面兩個在進行垃圾回收工作時,需要暫停整個運行環境,而只有垃圾回收程序在運行,因此,系統在垃圾回收時會有明顯的暫停,而且暫停時間會因為堆越大而越長。

為什么要分代

    分代的垃圾回收策略,是基于這樣一個事實:不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。

    在Java程序運行的過程中,會產生大量的對象,其中有些對象是與業務信息相關,比如Http請求中的Session對象、線程、Socket連接,這類對象跟業務直接掛鉤,因此生命周期比較長。但是還有一些對象,主要是程序運行過程中生成的臨時變量,這些對象生命周期會比較短,比如:String對象,由于其不變類的特性,系統會產生大量的這些對象,有些對象甚至只用一次即可回收。

    試想,在不進行對象存活時間區分的情況下,每次垃圾回收都是對整個堆空間進行回收,花費時間相對會長,同時,因為每次回收都需要遍歷所有存活對象,但實際上,對于生命周期長的對象而言,這種遍歷是沒有效果的,因為可能進行了很多次遍歷,但是他們依舊存在。因此,分代垃圾回收采用分治的思想,進行代的劃分,把不同生命周期的對象放在不同代上,不同代上采用最適合它的垃圾回收方式進行回收。

如何分代

    虛擬機中的共劃分為三個代:年輕代(Young Generation)、年老點(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類的類信息,與垃圾收集要收集的Java對象關系不大。年輕代和年老代的劃分是對垃圾收集影響比較大的。

年輕代:

    所有新生成的對象首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被復制到Survivor區(兩個中的一個),當這個 Survivor區滿時,此區的存活對象將被復制到另外一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區復制過來的并且此時還存活的對象,將被復制“年老區(Tenured)”。需要注意,Survivor的兩個區是對稱的,沒先后關系,所以同一個區中可能同時存在從Eden復制過來 對象,和從前一個Survivor復制過來的對象,而復制到年老區的只有從第一個Survivor去過來的對象。而且,Survivor區總有一個是空的。同時,根據程序需要,Survivor區是可以配置為多個的(多于兩個),這樣可以增加對象在年輕代中的存在時間,減少被放到年老代的可能。

年老代:

    在年輕代中經歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象。

持久代:

    用于存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進行設置。

1. Heap設定與垃圾回收

       Java Heap分為3個區,Young,Old和Permanent。Young保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old區。Permanent區則負責保存反射對象,本文不討論該區。

       JVM的Heap分配可以使用-X參數設定,

       -Xms 初始Heap大小

       -Xmx java heap最大值

       -Xmn young generation的heap大小 

       JVM 有2個GC線程。第一個線程負責回收Heap的Young區。第二個線程在Heap不足時,遍歷Heap,將Young 區升級為Older區。 Older區的大小等于-Xmx減去-Xmn,不能將-Xms的值設的過大,因為第二個線程被迫運行會降低JVM的性能。

       為什么一些程序頻繁發生GC?有如下原因:

       1)程序內調用了System.gc()或Runtime.gc()。

       2)一些中間件軟件調用自己的GC方法,此時需要設置參數禁止這些GC。

       3)Java的Heap太小,一般默認的Heap值都很小。

       4)頻繁實例化對象,Release對象。此時盡量保存并重用對象,例如使用StringBuffer()和String()。

       如果你發現每次GC后,Heap的剩余空間會是總空間的50%,這表示你的Heap處于健康狀態。許多Server端的Java程序每次GC后最好能有65%的剩余空間。

       經驗之談:

       1)Server端JVM最好將-Xms和-Xmx設為相同值。為了優化GC,最好讓-Xmn值約等于-Xmx的1/3[2]。

       2)一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒之內完成[2]。

       注意:

       1)增加Heap的大小雖然會降低GC的頻率,但也增加了每次GC的時間。并且GC運行時,所有的用戶線程將暫停,也 就是GC期間,Java應用程序不做任何工作。

       2)Heap大小并不決定進程的內存使用量。進程的內存使用量要大于-Xmx定義的值,因為Java為其他任務分配內存,例如每個線程的Stack等。

2.Stack的設定

       每個線程都有他自己的Stack。

       -Xss 每個線程的Stack大小 

       Stack的大小限制著線程的數量。如果Stack過大就好導致內存溢漏。-Xss參數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。

3.硬件環境

       硬件環境也影響GC的效率,例如機器的種類,內存,swap空間,和CPU的數量。

       如果你的程序需要頻繁創建很多transient對象,會導致JVM頻繁GC。這種情況你可以增加機器的內存,來減少Swap空間的使用[2]。

4.4種GC

       第一種為單線程GC,也是默認的GC。,該GC適用于單CPU機器。

       第二種為Throughput GC,是多線程的GC,適用于多CPU,使用大量線程的程序。第二種GC與第一種GC相似,不同在于GC在收集Young區是多線程的,但在Old區和第一種一樣,仍然采用單線程。-XX:+UseParallelGC參數啟動該GC。

       第三種為Concurrent Low Pause GC,類似于第一種,適用于多CPU,并要求縮短因GC造成程序停滯的時間。這種GC可以在Old區的回收同時,運行應用程序。-XX:+UseConcMarkSweepGC參數啟動該GC。

       第四種為Incremental Low Pause GC,適用于要求縮短因GC造成程序停滯的時間。這種GC可以在Young區回收的同時,回收一部分Old區對象。-Xincgc參數啟動該GC。

最后附上用java -X 命令查看JVM的配置說明:

D:/j2sdk15/bin>java -X

    -Xmixed           mixed mode execution (default)

    -Xint             interpreted mode execution only

    -Xbootclasspath:<directories and zip/jar files separated by ;>

                      set search path for bootstrap classes and resources

    -Xbootclasspath/a:<directories and zip/jar files separated by ;>

                      append to end of bootstrap class path

    -Xbootclasspath/p:<directories and zip/jar files separated by ;>

                      prepend in front of bootstrap class path

    -Xnoclassgc       disable class garbage collection

    -Xincgc           enable incremental garbage collection

    -Xloggc:<file>    log GC status to a file with time stamps

    -Xbatch           disable background compilation

    -Xms<size>        set initial Java heap size

    -Xmx<size>        set maximum Java heap size

    -Xss<size>        set java thread stack size

    -Xprof            output cpu profiling data

    -Xfuture          enable strictest checks, anticipating future default

    -Xrs              reduce use of OS signals by Java/VM (see documentation)

    -Xcheck:jni       perform additional checks for JNI functions

    -Xshare:off       do not attempt to use shared class data

    -Xshare:auto      use shared class data if possible (default)

    -Xshare:on        require using shared class data, otherwise fail.

The -X options are non-standard and subject to change without notice.

-----------------------------------------------------------------------
JVM配置參數中文說明:
-----------------------------------------------------------------------

1、-Xmixed           mixed mode execution (default)

 混合模式執行 

2、-Xint             interpreted mode execution only

 解釋模式執行 

3、-Xbootclasspath:<directories and zip/jar files separated by ;>

      set search path for bootstrap classes and resources

 設置zip/jar資源或者類(.class文件)存放目錄路徑 

3、-Xbootclasspath/a:<directories and zip/jar files separated by ;>

      append to end of bootstrap class path

 追加zip/jar資源或者類(.class文件)存放目錄路徑 

4、-Xbootclasspath/p:<directories and zip/jar files separated by ;>

      prepend in front of bootstrap class path

 預先加載zip/jar資源或者類(.class文件)存放目錄路徑 

5、-Xnoclassgc       disable class garbage collection

 關閉類垃圾回收功能 

6、-Xincgc           enable incremental garbage collection

 開啟類的垃圾回收功能 

7、-Xloggc:<file>    log GC status to a file with time stamps

 記錄垃圾回日志到一個文件。 

8、-Xbatch           disable background compilation

 關閉后臺編譯 

9、-Xms<size>        set initial Java heap size

 設置JVM初始化堆內存大小 

10、-Xmx<size>        set maximum Java heap size

 設置JVM最大的堆內存大小 

11、-Xss<size>        set java thread stack size

 設置JVM棧內存大小 

12、-Xprof            output cpu profiling data

 輸入CPU概要表數據 

13、-Xfuture          enable strictest checks, anticipating future default

 執行嚴格的代碼檢查,預測可能出現的情況 

14、-Xrs              reduce use of OS signals by Java/VM (see documentation)

 通過JVM還原操作系統信號 

15、-Xcheck:jni       perform additional checks for JNI functions

 對JNI函數執行檢查 

16、-Xshare:off       do not attempt to use shared class data

 盡可能不去使用共享類的數據 

17、-Xshare:auto      use shared class data if possible (default)

 盡可能的使用共享類的數據

18、-Xshare:on       require using shared class data, otherwise fail.

 盡可能的使用共享類的數據,否則運行失敗

The -X options are non-standard and subject to change without notice.

      調整JVM GC(Garbage Collection),可以極大的減少由于GC工作,而導致的程序運行中斷方面的問題,進而適當的提高Java程序的工作效率。但是調整GC是以個極為復雜的過程,

由于各個程序具備不同的特點,如:web和GUI程序就有很大區別(Web可以適當的停頓,但GUI停頓是客戶無法接受的),而且由于跑在各個機器上的配置不同(主要cup個數,內存不同),

所以使用的GC種類也會不同。接下來,我簡單介紹一下如何調整GC。

     首先說一下如何監視GC,你可以使用我以前文章中提到的JDK中的jstat工具 ,也可以在java程序啟動的opt里加上如下幾個參數(注:這兩個參數只針對SUN的HotSpot VM):

    -XX:-PrintGC     Print messages at garbage collection. Manageable.

    -XX:-PrintGC Details     Print more details at garbage collection. Manageable. (Introduced in 1.4.0.)

    -XX:-PrintGCTimeStamps     Print timestamps at garbage collection. Manageable (Introduced in 1.4.0.)

   當把-XX:-PrintGC Details 加入到java opt里以后可以看見如下輸出:

    [GC [DefNew: 34538K->2311K(36352K), 0.0232439 secs] 45898K->15874K(520320K), 0.0233874 secs]

    [Full GC [Tenured: 13563K->15402K(483968K), 0.2368177 secs] 21163K->15402K(520320K), [Perm : 28671K->28635K(28672K)], 0.2371537 secs]

    他們分別顯示了GC的過程,清理出了多少空間。第一行GC使用的是 ‘普通GC’(Minor Collections),第二行使用的是 ‘全GC’(Major Collections)。他們的區別很大,在第一行最后

我們可以看見他的時間是0.0233874秒,而第二行的Full GC的時間是0.2371537秒。第二行的時間是第一行的接近10倍,也就是我們這次調優的重點,減少Full GC 的次數,因為Full GC

會暫停程序比較長的時間,如果Full GC 的次數比較多。程序就會經常性的假死。當然這只是他們的表面現象,接下來我仔細介紹一下GC,和 Full GC(為后面的調優做準備)。

      我們知道Java和C++的區別主要是,Java不需要像c++那樣,由程序員主動的釋放內存。而是由JVM里的GC(Garbage Collection)來,在適當的時候替我們釋放內存。GC 的內部工作,

即GC的算法有很多種, 如:標記清除收集器,壓縮收集器,分代收集器等等。現在比較常用的是分代收集(也是SUN VM使用的),即將內存分為幾個區域,將不同生命周期的對象放在不同區域里

(新的對象會先 生成在Young area,在幾次GC以后,如過沒有收集到,就會逐漸升級到Tenured area)。在GC收集的時候,頻繁收集生命周期短的區域(Young area),因為這個區域內的

對象生命周期比較短,GC 效率也會比較高。而比較少的收集生命周期比較長的區域(Old area or Tenured area),以及基本不收集的永久區(Perm area)。

     注:Young area又分為三個區域分別叫Eden,和倆個Survivor spaces。Eden用來存放新的對象,Survivor spaces用于 新對象 升級到 Tenured area時的 拷貝。

     我們管收集 生命周期短的區域(Young area) 的收集叫 GC,而管收集 生命周期比較長的區域(Old area or Tenured area)的收集叫 Full GC,因為他們的收集算法不同,

所以使用的時間也會不同。我們要盡量減少 Full GC 的次數。

      接下來介紹一下 HotSpot VM GC 的種類,GC在 HotSpot VM 5.0里有四種。一種是默認的叫 serial collector,另外幾種分別叫throughput collector,concurrent 

low pause collector, incremental (sometimes called train) low pause collector(廢棄掉了)。以下是SUN的官方說明:  

   1. The throughput collector: this collector uses a parallel version of the young generation collector. It is used if the 

-XX:+UseParallelGC option is passed on the command line. The tenured generation collector is the same as the serial collector.

   2. The concurrent low pause collector: this collector is used if the -Xincgc&#8482; or -XX:+UseConcMarkSweepGC is passed on the command line.

 The concurrent collector is used to collect the tenured generation and does most of the collection concurrently with the execution of 

the application. The application is paused for short periods during the collection. A parallel version of the young generation copying

 collector is used with the concurrent collector. The concurrent low pause collector is used if the option -XX:+UseConcMarkSweepGC is

 passed on the command line.

   3. The incremental (sometimes called train) low pause collector: this collector is used only if -XX:+UseTrainGC is passed on the 

command line. This collector has not changed since the J2SE Platform version 1.4.2 and is currently not under active development. 

It will not be supported in future releases. Please see the 1.4.2 GC Tuning Document for information on this collector.

       簡單來說就是throughput collector和concurrent low pause collector:使用多線程的方式,利用多CUP來提高GC的效率,而throughput collector與concurrent 

low pause collector的去別是throughput collector只在young area使用使用多線程,而concurrent low pause collector則在tenured generation也使用多線程。

        根據官方文檔,他們倆個需要在多CPU的情況下,才能發揮作用。在一個CPU的情況下,會不如默認的serial collector,因為線程管理需要耗費CPU資源。而在兩個CPU的情況下,

也挺高不大。只是在更多CPU的情況下,才會有所提高。當然 concurrent low pause collector有一種模式可以在CPU較少的機器上,提供盡可能少的停頓的模式,見下文。

        當要使用throughput collector時,在java opt里加上-XX:+UseParallelGC,啟動 throughput collector收集。也可加上-XX:ParallelGCThreads=<desired number>來改變線程數。

還有兩個參數 -XX:MaxGCPauseMillis=<nnn>和 -XX:GCTimeRatio=& lt;nnn>,MaxGCPauseMillis=<nnn>用來控制最大暫停時間,而-XX: GCTimeRatio可以提高 GC說占CPU的比,

以最大話的減小heap。

      當要使用 concurrent low pause collector時,在java的opt里加上 -XX:+UseConcMarkSweepGC。concurrent low pause collector還有一種為CPU少的機器

準備的模式,叫Incremental mode。這種模式使用一個CPU來在程序運行的過程中GC,只用很少的時間暫停程序,檢查對象存活。

        在Incremental mode里,每個收集過程中,會暫停兩次,第二次略長。第一次用來,簡單從root查詢存活對象。第二次用來,詳細檢查存活對象。整個過程如下:  

    * stop all application threads; do the initial mark; resume all application threads(第一次暫停,初始話標記)

    * do the concurrent mark (uses one procesor for the concurrent work)(運行是標記)

    * do the concurrent pre-clean (uses one processor for the concurrent work)(準備清理)

    * stop all application threads; do the remark; resume all application threads(第二次暫停,標記,檢查)

    * do the concurrent sweep (uses one processor for the concurrent work)(運行過程中清理)

    * do the concurrent reset (uses one processor for the concurrent work)(復原)

       當要使用Incremental mode時,需要使用以下幾個變量:

       -XX:+CMSIncrementalMode default: disabled 啟動i-CMS模式(must with -

XX:+UseConcMarkSweepGC)

       -XX:+CMSIncrementalPacing default: disabled 提供自動校正功能

       -XX:CMSIncrementalDutyCycle=<N> default: 50 啟動CMS的上線

       -XX:CMSIncrementalDutyCycleMin=<N> default: 10 啟動CMS的下線

       -XX:CMSIncrementalSafetyFactor=<N> default: 10 用來計算循環次數

       -XX:CMSIncrementalOffset=<N> default: 0 最小循環次數(This is the percentage (0-

100) by which the incremental mode duty cycle is shifted to the right within the period

between minor collections.)

       -XX:CMSExpAvgFactor=<N> default: 25 提供一個指導收集數

      SUN推薦的使用參數是:

        -XX:+UseConcMarkSweepGC /

        -XX:+CMSIncrementalMode /

        -XX:+CMSIncrementalPacing /

        -XX:CMSIncrementalDutyCycleMin=0 /

        -XX:CMSIncrementalDutyCycle=10 /

        -XX:+PrintGC Details /

        -XX:+PrintGCTimeStamps /

        -XX:-TraceClassUnloading

       注:如果使用throughput collector和concurrent low pause collector,這兩種垃圾收集器,需要適當的挺高內存大小,以為多線程做準備。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!