1. Heap設(shè)定與垃圾回收
Java Heap分為3個(gè)區(qū),Young,Old和Permanent。Young保存剛實(shí)例化的對(duì)象。當(dāng)該區(qū)被填滿時(shí),GC會(huì)將對(duì)象移到Old區(qū)。Permanent區(qū)則負(fù)責(zé)保存反射對(duì)象,本文不討論該區(qū)。
JVM的Heap分配可以使用-X參數(shù)設(shè)定,
-Xms 初始Heap大小
-Xmx java heap最大值
-Xmn young generation的heap大小
JVM 有2個(gè)GC線程。第一個(gè)線程負(fù)責(zé)回收Heap的Young區(qū)。第二個(gè)線程在Heap不足時(shí),遍歷Heap,將Young 區(qū)升級(jí)為Older區(qū)。 Older區(qū)的大小等于-Xmx減去-Xmn,不能將-Xms的值設(shè)的過(guò)大,因?yàn)榈诙€(gè)線程被迫運(yùn)行會(huì)降低JVM的性能。
為什么一些程序頻繁發(fā)生GC?有如下原因:
1)程序內(nèi)調(diào)用了System.gc()或Runtime.gc()。
2)一些中間件軟件調(diào)用自己的GC方法,此時(shí)需要設(shè)置參數(shù)禁止這些GC。
3)Java的Heap太小,一般默認(rèn)的Heap值都很小。
4)頻繁實(shí)例化對(duì)象,Release對(duì)象。此時(shí)盡量保存并重用對(duì)象,例如使用StringBuffer()和String()。
如果你發(fā)現(xiàn)每次GC后,Heap的剩余空間會(huì)是總空間的50%,這表示你的Heap處于健康狀態(tài)。許多Server端的Java程序每次GC后最好能有65%的剩余空間。
經(jīng)驗(yàn)之談:
1)Server端JVM最好將-Xms和-Xmx設(shè)為相同值。為了優(yōu)化GC,最好讓-Xmn值約等于-Xmx的1/3[2]。
2)一個(gè)GUI程序最好是每10到20秒間運(yùn)行一次GC,每次在半秒之內(nèi)完成[2]。
注意:
1)增加Heap的大小雖然會(huì)降低GC的頻率,但也增加了每次GC的時(shí)間。并且GC運(yùn)行時(shí),所有的用戶線程將暫停,也 就是GC期間,Java應(yīng)用程序不做任何工作。
2)Heap大小并不決定進(jìn)程的內(nèi)存使用量。進(jìn)程的內(nèi)存使用量要大于-Xmx定義的值,因?yàn)镴ava為其他任務(wù)分配內(nèi)存,例如每個(gè)線程的Stack等。
2.Stack的設(shè)定
每個(gè)線程都有他自己的Stack。
-Xss 每個(gè)線程的Stack大小
Stack的大小限制著線程的數(shù)量。如果Stack過(guò)大就好導(dǎo)致內(nèi)存溢漏。-Xss參數(shù)決定Stack大小,例如-Xss1024K。如果Stack太小,也會(huì)導(dǎo)致Stack溢漏。
3.硬件環(huán)境
硬件環(huán)境也影響GC的效率,例如機(jī)器的種類,內(nèi)存,swap空間,和CPU的數(shù)量。
如果你的程序需要頻繁創(chuàng)建很多transient對(duì)象,會(huì)導(dǎo)致JVM頻繁GC。這種情況你可以增加機(jī)器的內(nèi)存,來(lái)減少Swap空間的使用[2]。
4.4種GC
第一種為單線程GC,也是默認(rèn)的GC。,該GC適用于單CPU機(jī)器。
第二種為Throughput GC,是多線程的GC,適用于多CPU,使用大量線程的程序。第二種GC與第一種GC相似,不同在于GC在收集Young區(qū)是多線程的,但在Old區(qū)和第一種一樣,仍然采用單線程。-XX:+UseParallelGC參數(shù)啟動(dòng)該GC。
第三種為Concurrent Low Pause GC,類似于第一種,適用于多CPU,并要求縮短因GC造成程序停滯的時(shí)間。這種GC可以在Old區(qū)的回收同時(shí),運(yùn)行應(yīng)用程序。-XX:+UseConcMarkSweepGC參數(shù)啟動(dòng)該GC。
第四種為Incremental Low Pause GC,適用于要求縮短因GC造成程序停滯的時(shí)間。這種GC可以在Young區(qū)回收的同時(shí),回收一部分Old區(qū)對(duì)象。-Xincgc參數(shù)啟動(dòng)該GC。
最后附上用java -X 命令查看JVM的配置說(shuō)明:
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配置參數(shù)中文說(shuō)明:
-----------------------------------------------------------------------
1、-Xmixed mixed mode execution (default)
混合模式執(zhí)行
2、-Xint interpreted mode execution only
解釋模式執(zhí)行
3、-Xbootclasspath:<directories and zip/jar files separated by ;>
set search path for bootstrap classes and resources
設(shè)置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
預(yù)先加載zip/jar資源或者類(.class文件)存放目錄路徑
5、-Xnoclassgc disable class garbage collection
關(guān)閉類垃圾回收功能
6、-Xincgc enable incremental garbage collection
開啟類的垃圾回收功能
7、-Xloggc:<file> log GC status to a file with time stamps
記錄垃圾回日志到一個(gè)文件。
8、-Xbatch disable background compilation
關(guān)閉后臺(tái)編譯
9、-Xms<size> set initial Java heap size
設(shè)置JVM初始化堆內(nèi)存大小
10、-Xmx<size> set maximum Java heap size
設(shè)置JVM最大的堆內(nèi)存大小
11、-Xss<size> set java thread stack size
設(shè)置JVM棧內(nèi)存大小
12、-Xprof output cpu profiling data
輸入CPU概要表數(shù)據(jù)
13、-Xfuture enable strictest checks, anticipating future default
執(zhí)行嚴(yán)格的代碼檢查,預(yù)測(cè)可能出現(xiàn)的情況
14、-Xrs reduce use of OS signals by Java/VM (see documentation)
通過(guò)JVM還原操作系統(tǒng)信號(hào)
15、-Xcheck:jni perform additional checks for JNI functions
對(duì)JNI函數(shù)執(zhí)行檢查
16、-Xshare:off do not attempt to use shared class data
盡可能不去使用共享類的數(shù)據(jù)
17、-Xshare:auto use shared class data if possible (default)
盡可能的使用共享類的數(shù)據(jù)
18、-Xshare:on require using shared class data, otherwise fail.
盡可能的使用共享類的數(shù)據(jù),否則運(yùn)行失敗
The -X options are non-standard and subject to change without notice.
調(diào)整JVM GC(Garbage Collection),可以極大的減少由于GC工作,而導(dǎo)致的程序運(yùn)行中斷方面的問(wèn)題,進(jìn)而適當(dāng)?shù)奶岣逬ava程序的工作效率。但是調(diào)整GC是以個(gè)極為復(fù)雜的過(guò)程,
由于各個(gè)程序具備不同的特點(diǎn),如:web和GUI程序就有很大區(qū)別(Web可以適當(dāng)?shù)耐nD,但GUI停頓是客戶無(wú)法接受的),而且由于跑在各個(gè)機(jī)器上的配置不同(主要cup個(gè)數(shù),內(nèi)存不同),
所以使用的GC種類也會(huì)不同。接下來(lái),我簡(jiǎn)單介紹一下如何調(diào)整GC。
首先說(shuō)一下如何監(jiān)視GC,你可以使用我以前文章中提到的JDK中的jstat工具 ,也可以在java程序啟動(dòng)的opt里加上如下幾個(gè)參數(shù)(注:這兩個(gè)參數(shù)只針對(duì)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.)
當(dāng)把-XX:-PrintGC Details 加入到j(luò)ava opt里以后可以看見(jiàn)如下輸出:
[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的過(guò)程,清理出了多少空間。第一行GC使用的是 ‘普通GC’(Minor Collections),第二行使用的是 ‘全GC’(Major Collections)。他們的區(qū)別很大,在第一行最后
我們可以看見(jiàn)他的時(shí)間是0.0233874秒,而第二行的Full GC的時(shí)間是0.2371537秒。第二行的時(shí)間是第一行的接近10倍,也就是我們這次調(diào)優(yōu)的重點(diǎn),減少Full GC 的次數(shù),因?yàn)镕ull GC
會(huì)暫停程序比較長(zhǎng)的時(shí)間,如果Full GC 的次數(shù)比較多。程序就會(huì)經(jīng)常性的假死。當(dāng)然這只是他們的表面現(xiàn)象,接下來(lái)我仔細(xì)介紹一下GC,和 Full GC(為后面的調(diào)優(yōu)做準(zhǔn)備)。
我們知道Java和C++的區(qū)別主要是,Java不需要像c++那樣,由程序員主動(dòng)的釋放內(nèi)存。而是由JVM里的GC(Garbage Collection)來(lái),在適當(dāng)?shù)臅r(shí)候替我們釋放內(nèi)存。GC 的內(nèi)部工作,
即GC的算法有很多種, 如:標(biāo)記清除收集器,壓縮收集器,分代收集器等等?,F(xiàn)在比較常用的是分代收集(也是SUN VM使用的),即將內(nèi)存分為幾個(gè)區(qū)域,將不同生命周期的對(duì)象放在不同區(qū)域里
(新的對(duì)象會(huì)先 生成在Young area,在幾次GC以后,如過(guò)沒(méi)有收集到,就會(huì)逐漸升級(jí)到Tenured area)。在GC收集的時(shí)候,頻繁收集生命周期短的區(qū)域(Young area),因?yàn)檫@個(gè)區(qū)域內(nèi)的
對(duì)象生命周期比較短,GC 效率也會(huì)比較高。而比較少的收集生命周期比較長(zhǎng)的區(qū)域(Old area or Tenured area),以及基本不收集的永久區(qū)(Perm area)。
注:Young area又分為三個(gè)區(qū)域分別叫Eden,和倆個(gè)Survivor spaces。Eden用來(lái)存放新的對(duì)象,Survivor spaces用于 新對(duì)象 升級(jí)到 Tenured area時(shí)的 拷貝。
我們管收集 生命周期短的區(qū)域(Young area) 的收集叫 GC,而管收集 生命周期比較長(zhǎng)的區(qū)域(Old area or Tenured area)的收集叫 Full GC,因?yàn)樗麄兊氖占惴ú煌?/div>
所以使用的時(shí)間也會(huì)不同。我們要盡量減少 Full GC 的次數(shù)。
接下來(lái)介紹一下 HotSpot VM GC 的種類,GC在 HotSpot VM 5.0里有四種。一種是默認(rèn)的叫 serial collector,另外幾種分別叫throughput collector,concurrent
low pause collector, incremental (sometimes called train) low pause collector(廢棄掉了)。以下是SUN的官方說(shuō)明:
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™ 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.
簡(jiǎn)單來(lái)說(shuō)就是throughput collector和concurrent low pause collector:使用多線程的方式,利用多CUP來(lái)提高GC的效率,而throughput collector與concurrent
low pause collector的去別是throughput collector只在young area使用使用多線程,而concurrent low pause collector則在tenured generation也使用多線程。
根據(jù)官方文檔,他們倆個(gè)需要在多CPU的情況下,才能發(fā)揮作用。在一個(gè)CPU的情況下,會(huì)不如默認(rèn)的serial collector,因?yàn)榫€程管理需要耗費(fèi)CPU資源。而在兩個(gè)CPU的情況下,
也挺高不大。只是在更多CPU的情況下,才會(huì)有所提高。當(dāng)然 concurrent low pause collector有一種模式可以在CPU較少的機(jī)器上,提供盡可能少的停頓的模式,見(jiàn)下文。
當(dāng)要使用throughput collector時(shí),在java opt里加上-XX:+UseParallelGC,啟動(dòng) throughput collector收集。也可加上-XX:ParallelGCThreads=<desired number>來(lái)改變線程數(shù)。
還有兩個(gè)參數(shù) -XX:MaxGCPauseMillis=<nnn>和 -XX:GCTimeRatio=& lt;nnn>,MaxGCPauseMillis=<nnn>用來(lái)控制最大暫停時(shí)間,而-XX: GCTimeRatio可以提高 GC說(shuō)占CPU的比,
以最大話的減小heap。
當(dāng)要使用 concurrent low pause collector時(shí),在java的opt里加上 -XX:+UseConcMarkSweepGC。concurrent low pause collector還有一種為CPU少的機(jī)器
準(zhǔn)備的模式,叫Incremental mode。這種模式使用一個(gè)CPU來(lái)在程序運(yùn)行的過(guò)程中GC,只用很少的時(shí)間暫停程序,檢查對(duì)象存活。
在Incremental mode里,每個(gè)收集過(guò)程中,會(huì)暫停兩次,第二次略長(zhǎng)。第一次用來(lái),簡(jiǎn)單從root查詢存活對(duì)象。第二次用來(lái),詳細(xì)檢查存活對(duì)象。整個(gè)過(guò)程如下:
* stop all application threads; do the initial mark; resume all application threads(第一次暫停,初始話標(biāo)記)
* do the concurrent mark (uses one procesor for the concurrent work)(運(yùn)行是標(biāo)記)
* do the concurrent pre-clean (uses one processor for the concurrent work)(準(zhǔn)備清理)
* stop all application threads; do the remark; resume all application threads(第二次暫停,標(biāo)記,檢查)
* do the concurrent sweep (uses one processor for the concurrent work)(運(yùn)行過(guò)程中清理)
* do the concurrent reset (uses one processor for the concurrent work)(復(fù)原)
當(dāng)要使用Incremental mode時(shí),需要使用以下幾個(gè)變量:
-XX:+CMSIncrementalMode default: disabled 啟動(dòng)i-CMS模式(must with -
XX:+UseConcMarkSweepGC)
-XX:+CMSIncrementalPacing default: disabled 提供自動(dòng)校正功能
-XX:CMSIncrementalDutyCycle=<N> default: 50 啟動(dòng)CMS的上線
-XX:CMSIncrementalDutyCycleMin=<N> default: 10 啟動(dòng)CMS的下線
-XX:CMSIncrementalSafetyFactor=<N> default: 10 用來(lái)計(jì)算循環(huán)次數(shù)
-XX:CMSIncrementalOffset=<N> default: 0 最小循環(huán)次數(shù)(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 提供一個(gè)指導(dǎo)收集數(shù)
SUN推薦的使用參數(shù)是:
-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,這兩種垃圾收集器,需要適當(dāng)?shù)耐Ω邇?nèi)存大小,以為多線程做準(zhǔn)備。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。