說明本文是閱讀《Java性能權(quán)威指南》的第五章節(jié)梳理內(nèi)容,不是本人原創(chuàng)忱叭,覺得寫的非常好隔崎,特意總結(jié)下,所以有了下文韵丑。
1.GC作用
主要做三件事情:
-
查找不可用的對象爵卒。
不能采用簡單的引用計數(shù)功能,因?yàn)橛蓄愃朴陔p向鏈表的將無法清除撵彻。 -
回收垃圾對象占用內(nèi)存
不同的垃圾回收器钓株,采用不同的算法,采用單線程或多線程來回收垃圾對
象千康。 -
內(nèi)存碎片的整理
將回收后的對象進(jìn)行壓縮形成大的空閑區(qū)域享幽。
2.垃圾回收共有特性
均采用分代回收形式
分代可以將堆空間劃分成不同的代,減少每個代的大小拾弃,有利于掃描垃圾對象值桩。所有的GC回收算法在新生代都會暫停所有應(yīng)用程序線程
新生代直接涉及到的是應(yīng)用程序?qū)ο蟮姆峙洌诜峙涞臅r候豪椿,會更改對象的空間奔坟。** 新生代的垃圾回收稱為Minor GC**
新生代初始分配空間為Enden携栋,要么對象移到老年代,要么移到Survior空間咳秉。** 老年代空間即將占滿時候回收婉支,采用不同垃圾回收算法**
簡單垃圾回收算法: 暫停應(yīng)用程序線程,直接進(jìn)行Full GC澜建。
CMS/G1: 盡量減少停頓向挖,會占用更多CPU稱為Concurrent收集器。
3. GC垃圾回收算法選擇
1.使用內(nèi)存小于100M
使用Serial 垃圾收集器炕舵。
2. Concurrent or Throughput
單核心CPU或者cpu很忙:利用Throughput另玖,處理應(yīng)用程序的批處理任務(wù)伸辟,通秤纯可以獲得更好的性能爱沟,因?yàn)樵赾pu很忙的時候,CMS多線程和應(yīng)用程序爭奪資源會造成系統(tǒng)運(yùn)行更慢奸攻。
多核CPU或CPU資源不忙:
采用Concurrent收集器可以獲得更好的性能蒜危。
3. CMS 和 Throughput 的CPU利用率特點(diǎn):
Throughput: 在進(jìn)行Full GC或Minor GC 都會占用100%cpu;在90%和99%的響應(yīng)時間上更有優(yōu)勢,如果超負(fù)荷運(yùn)行大量Full GC睹耐,則切換到Concurrent性能更好辐赞。
CMS: 在后臺垃圾回收線程和應(yīng)用程序線程同時運(yùn)行,CPU利用率更平滑疏橄,偶爾達(dá)到100%占拍。在CPU資源不夠時候,可能會退化到Serial方式捎迫,CPU占不滿晃酒,性能比Throughput 差。
4. CMS VS G1
基本原則:堆內(nèi)存小于4G情況下窄绒,建議用CMS 贝次,性能更好;大型堆采用G1更好彰导。
CMS
CMS后臺線程需要掃描整個老年代內(nèi)存蛔翅,掃描時間與堆大小關(guān)系密切,如果在堆未填滿之前位谋,CMS后臺線程停止掃描山析,直接回收對象,則發(fā)生并發(fā)失效掏父。一旦發(fā)生了Concurrent Mode Failure笋轨,則處理Full GC的只有一個線程,性能損耗嚴(yán)重,CMS并發(fā)模式失效同時也會受到程序內(nèi)存分配的影響爵政。另外堆的碎片化也會導(dǎo)致Full GC仅讽。
G1
將堆分為多個區(qū)域,更利于使用多線程分擔(dān)掃描老年代钾挟,如果后臺線程跟不上處理速度也會發(fā)生并發(fā)模式失效的問題洁灵;也會發(fā)生堆的內(nèi)存碎片化,不過比CMS要好掺出。
此外說明:Throughput 比CMS徽千、G1 更老,所以經(jīng)過長期驗(yàn)證汤锨,穩(wěn)定性罐栈,可調(diào)整參數(shù)更多,相反G1新的垃圾回收器泥畅,容易遇到極端情況多。
5. GC調(diào)優(yōu)基礎(chǔ)
內(nèi)存大小調(diào)節(jié)
堆大小設(shè)置:
設(shè)置過欣欧:導(dǎo)致一直在GC位仁,程序執(zhí)行速度慢。
設(shè)置過大:
1.導(dǎo)致垃圾回收時間長方椎,停頓時間短聂抢,但是持續(xù)時間會讓程序整體性能變慢。
2.JVM虛擬內(nèi)存如果占用了系統(tǒng)的虛擬內(nèi)存棠众,F(xiàn)ull GC性能將會非常糟糕琳疏。
堆設(shè)置的首要原則
永遠(yuǎn)不要將堆的總大小設(shè)置超過機(jī)器的物理內(nèi)存,特別是有多個JVM在跑的時候闸拿,通常情況對于普通的操作系統(tǒng)需要預(yù)留1G的內(nèi)存給操作系統(tǒng)空盼。
堆大小控制參數(shù)
-XmsN 設(shè)置初始值
-XmxN 設(shè)置最大值
默認(rèn)值取決于操作系統(tǒng)、系統(tǒng)內(nèi)存大小新荤、JVM和命令行標(biāo)志揽趾,堆大小調(diào)節(jié)是JVM自適應(yīng)調(diào)節(jié)核心。
堆默認(rèn)值
經(jīng)驗(yàn)法則:
一次Full GC后盡量保持70%內(nèi)存可用苛骨。
設(shè)置方法:在穩(wěn)定運(yùn)行程序的時候通過Jconsole連接程序進(jìn)行Full GC觀察有多少內(nèi)存被占用篱瞎。
初始值和最大值設(shè)置一樣可以稍微提高GC運(yùn)行效率,調(diào)整盡量調(diào)整算法痒芝。
代空間調(diào)整
需要調(diào)整的原因:給新生代分配的比較大俐筋,垃圾收集的頻率降低,從新生代晉級的也比較少严衬,但是相應(yīng)的老年代的相對較小澄者,比較容易被填滿,從而造成Full GC,所以需要找個平衡點(diǎn)闷哆。
所有的GC算法都采用同一套標(biāo)志來設(shè)置代的大醒堋:
-XX:NewRatio=N
設(shè)置新生代與老年代的空間占比率
-XX:NewSize= N
設(shè)置新生代的空間大小
-XX:MaxNewSize=N
設(shè)置新生代空間的最大大小
-XmnN
將新生代的NewSize和MaxNewSize設(shè)置為同一個值。
最初新生代空間由NewRadtio決定抱怔,默認(rèn)設(shè)置為2.
新生代空間= 初始堆大小/(1+NewRadio) 即新生代空間為初始堆的33%劣坊。
NewSize 比NewRadio優(yōu)先級更高。
建議: 如果堆大小固定屈留,則新生代可以設(shè)置為固定值局冰;否則可以設(shè)置為按照比例。
整個堆空間的劃分是由新生代的大小來決定的灌危。
永生代/元空間調(diào)整
- Java7保存的是類元數(shù)據(jù)信息康二,稱為永久代,還保存一些類無關(guān)的雜項(xiàng)信息勇蝙。
- Java8改名永生代為元空間只對編譯器和JVM運(yùn)行時候有用沫勿。
永久代/元空間默認(rèn)大小:
對永久代而言:
可以通過-XX:PermSize=N / -XX:MaxPermSize=N類設(shè)置
對于元空間而言:
可以通過-XX:MetaspaceSize=N/ -XX:MaxMetaspaceSize= N 來設(shè)置
增加啟動速度可以通過增加用具帶或元空間達(dá)到味混,特別是才啟動有大量Full GC产雹,
通常設(shè)置為128MB/192MB
同樣會被垃圾回收,不是永久存在翁锡。
比如類加載器蔓挖,通過jmap –permstat 或-clstats來查看輸出類加載器信息。
6. GC的并發(fā)控制
控制參數(shù): -XX:ParallelGCThreads=N
影響下面的線程數(shù)目:
-XX:+UseParallelGC 收集新生代空間
-XX:+UseParallelOldGC 收集老生代空間
-XX:+UseNewParNewGC: 收集新生代空間
-XX:+UseG1GC 收集新生代空間
CMS收集器的STW階段(非Full GC)
G1收集器的STW階段(非Full GC)
GC默認(rèn)線程數(shù):
1馆衔、在小于8個cpu的時候瘟判,一個cpu啟動一個線程。
2角溃、一旦超過8個則:parallelGCThread= 8 + ((N-8)*5/8)
3拷获、在8核或更少核心,JVM 100%占用cpu减细,在更多核心上刀诬,運(yùn)行垃圾回收器會更多占用cpu,例如一個16核心cpu邪财,如果運(yùn)行4個JVM陕壹,則默認(rèn)一個13個線程,則嚴(yán)重影響程序性能树埠,建議每個JVM設(shè)置4個垃圾回收線程比較合理糠馆。
7.自適應(yīng)調(diào)節(jié)
JVM自動運(yùn)行的時候,根據(jù)默認(rèn)的指標(biāo)自動調(diào)整代的大小盡量的滿足目標(biāo)怎憋。
好處:
1又碌、以為小型程序不需要為指定過大的堆而擔(dān)心九昧。
2、不需要擔(dān)心堆大小毕匀,JVM自動根據(jù)優(yōu)化目標(biāo)調(diào)整堆的大小铸鹰。
3、缺點(diǎn):調(diào)整需要時間開銷皂岔,如果已經(jīng)做了優(yōu)化蹋笼,可以考慮關(guān)閉自適應(yīng)調(diào)整。
通過-XX:+UseAdaptiveSizePolicy 在全局范圍關(guān)閉自適應(yīng)調(diào)整功能躁垛。
如果堆最大和最小設(shè)置相同剖毯,新生代的最大最小設(shè)置相同,則將會自動關(guān)閉自適應(yīng)調(diào)整教馆。
4逊谋、如果設(shè)置-XX:+PrintAdaptiveSizePolicy標(biāo)志,則垃圾回收日志打印不同代的調(diào)整細(xì)節(jié)
8.垃圾回收工具
1土铺、判斷垃圾回收性能好壞需要日志
-verbose:gc 或-XX:+PrintGC 這兩個標(biāo)示中的任意一個可以創(chuàng)建基本的GC日志
2胶滋、詳細(xì)垃圾回收日志
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps 或-XX:+PrintGCDateStamps 便于查看幾次垃圾回收操作之間的時間。
前者時間戳是基于0(JVM啟動時間)的悲敷;后者基于真正日期镀钓,需要耗費(fèi)更多性能。
3镀迂、垃圾回收結(jié)果輸出到日志:
-Xloggc:filename
-XX:+UseGCLogfileRotation –XX:NumberOfGCLogFileRotation=N –XX:GCLogfileSize=N
來設(shè)置gc日志輪詢打印和輪詢打印的日志文件數(shù)、日志文件大小唤蔗。
4探遵、利用工具查看日志
GC Histogram 讀取日志生成圖形表格
Jconsole 內(nèi)存板可以查看堆的使用情況。
Jstat –gcutil 能夠打印各個區(qū)的占用百分比和垃圾回收情況妓柜,
Jstat –gcutil process_id 1000 【每隔1s打印一次情況】