JVM調優新(轉)

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=<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,這兩種垃圾收集器,需要適當的挺高內存大小,以爲多線程做準備。

發佈了94 篇原創文章 · 獲贊 0 · 訪問量 8940
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章