JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫(xiě),是實(shí)現(xiàn)java跨平臺(tái)特性的關(guān)鍵特漩。Java虛擬機(jī)在執(zhí)行字節(jié)碼時(shí)拷呆,把字節(jié)碼解釋成具體平臺(tái)上的機(jī)器指令進(jìn)行執(zhí)行拴泌,這樣實(shí)現(xiàn)了Java“一次編譯杆怕,到處運(yùn)行”捷绑。
JVM新生代
- 新生代=1個(gè)eden區(qū)+2個(gè)Survivor區(qū)
- -Xmn 年輕代大杏蹼(早期版本)
-XX:NewSize, -XX: MaxNewSize (設(shè)置年輕代大小(for 1.3/1.4)默認(rèn)值大小調(diào)整為個(gè)堆的3/8) - -XX: NewRatio
年輕代(包含Eden和兩個(gè)Survivor區(qū))與年老代的比值(除去持久代)Xms=Xmx并且設(shè)置了Xmn的情況下履磨,改參數(shù)不需要設(shè)置蛉抓。 - -XX.SurvivorRatio
Eden區(qū)與Survivor區(qū)的大小比值,設(shè)置為8剃诅,則兩個(gè)Survivor區(qū)與一個(gè)Eden區(qū)的比值為2:8巷送,一個(gè)Survivor區(qū)占整個(gè)年輕代的1/10 - 用來(lái)存放JVM剛分配的Java對(duì)象。
Java年老代(tenured generation)
- 老年代=整個(gè)堆 - 年輕代大小 - 持久代大小
- 年輕代中經(jīng)過(guò)垃圾回收沒(méi)有回收掉的對(duì)象被復(fù)制到年老代矛辕。
- 老年代存儲(chǔ)對(duì)象比年輕代年齡大的多笑跛,而且不乏大對(duì)象。
- 新建的對(duì)象也有可能直接進(jìn)入老年代
- 大對(duì)象聊品,可通過(guò)啟動(dòng)參數(shù)設(shè)置-XX: PretenureSizeThreshold=1024 (單位為字節(jié)飞蹂,默認(rèn)為0)來(lái)代表超過(guò)多大時(shí)就不在新生代分配,而是直接在老年代分配翻屈。
- 大的數(shù)組對(duì)象陈哑,且數(shù)組中午引用外部對(duì)象。
- 老年代大小無(wú)配置參數(shù)
Java持久代(perm generation)
- 持久代=整個(gè)堆 - 年輕代大小 - 老年代大小
- -XX:PermSize -XX:MaxPermSize
設(shè)置持久代的大小伸眶,一般情況推薦把-XX:PermSize設(shè)置成XX:MaxPermSize的相同值惊窖,因?yàn)橛谰脦Т笮〉恼{(diào)整會(huì)導(dǎo)致堆內(nèi)存需要觸發(fā)fgc. - 存放Class,Method元信息,其大小與項(xiàng)目的規(guī)模厘贼,類界酒,方法的數(shù)量有關(guān)。一般設(shè)置為128M就足夠嘴秸,設(shè)置原則是預(yù)留30%的空間毁欣。
- 永久代的回收方式
- 常量池中的常量庇谆,無(wú)用的類信息,常量的回收很簡(jiǎn)單凭疮,沒(méi)有引用了就會(huì)被回收饭耳。
- 對(duì)于無(wú)用的類進(jìn)行回收,必須保證三點(diǎn):
- 類的所有實(shí)例都已經(jīng)被回收
- 加載類的ClassLoader已經(jīng)被回收
- 類對(duì)象的Class對(duì)象沒(méi)有被引用(即沒(méi)有通過(guò)反射引用該類的地方)
JVM內(nèi)存垃圾回收
JVM垃圾收集算法
- 引用計(jì)數(shù)算法
每個(gè)對(duì)象有一個(gè)引用計(jì)數(shù)屬性哭尝,新增一個(gè)引用時(shí)計(jì)數(shù)加1哥攘,引用釋放時(shí)計(jì)數(shù)減1剖煌,計(jì)數(shù)為0時(shí)可以回收材鹦。此方法簡(jiǎn)單,無(wú)法解決對(duì)象互斥循環(huán)引用的問(wèn)題耕姊,還有一個(gè)問(wèn)題是如何解決精確計(jì)數(shù)桶唐。此種方式已經(jīng)不再使用。 - 根搜索算法
從GC Roots開(kāi)始向下檢索茉兰,搜索所走過(guò)的路徑為引用鏈尤泽,當(dāng)一個(gè)對(duì)象到GC鏈沒(méi)有一個(gè)引用鏈相連時(shí),則證明對(duì)象是不可用的规脸,不可達(dá)對(duì)象坯约。
在Java語(yǔ)言中,GC Roots包括:- 虛擬機(jī)棧中引用的對(duì)象
- 方法區(qū)中類靜態(tài)屬性實(shí)體引用的對(duì)象莫鸭。
- 方法區(qū)中常量引用的對(duì)象
- 本地方法棧中JNI引用的對(duì)象
JVM垃圾回收算法
- 復(fù)制算法(Copying)
復(fù)制算法采用從根集合掃描闹丐,并將存活的對(duì)象復(fù)制到一塊新的,沒(méi)有使用過(guò)空間中被因,這種算法當(dāng)控件存活的對(duì)象比較少時(shí)卿拴,極為高效,但是此算法用于新生代內(nèi)存回收梨与,從E區(qū)回收到S0或者S1堕花。
標(biāo)記清除算法
標(biāo)記-清除算法采用從根集合進(jìn)行掃描,對(duì)存活的對(duì)象標(biāo)記粥鞋,標(biāo)記完畢后缘挽,再掃描整個(gè)空間中未被標(biāo)記的對(duì)象,進(jìn)行回收呻粹。
標(biāo)記清除算法不需要進(jìn)行對(duì)象的移動(dòng)壕曼,并且僅對(duì)不存貨的對(duì)象進(jìn)行處理,在存活對(duì)象比較多的情況下極為高效尚猿,但是由于標(biāo)記清除算法直接回收不存活的對(duì)象窝稿,因此會(huì)造成內(nèi)存碎片。標(biāo)記整理算法
標(biāo)記整理算法采用標(biāo)記-清除算法一樣的方式進(jìn)行對(duì)象的標(biāo)記凿掂,但在清除時(shí)不同伴榔,在回收不存活的對(duì)象占用空間后纹蝴,會(huì)將所有存活對(duì)象往左端空閑空間移動(dòng),并更新對(duì)應(yīng)的指針踪少。標(biāo)記整理算法是在標(biāo)記清除算法的基礎(chǔ)上塘安,又進(jìn)行了對(duì)象的移動(dòng),因此成本更高援奢,但是卻解決了內(nèi)存碎片的問(wèn)題兼犯。-
回收的方式
- 串行回收:gc單線程內(nèi)存回收,會(huì)暫停所有用戶線程
- 并行回收:收集是指多個(gè)gc線程并行工作集漾,但此時(shí)用戶線程是暫停的切黔,所以 Serial是串行的,Parallel收集器是并行的具篇,而CMS收集器是并發(fā)的纬霞。
- 并發(fā)回收:是指用戶線程同事執(zhí)行(不一定是并行,可能交替驱显,但總體上是在同時(shí)執(zhí)行)诗芜,不需要停頓用戶線程——其實(shí)在CMS中用戶線程還是需要停頓的,只是非常短埃疫,gc線程在另一個(gè)CPU上執(zhí)行伏恐。
JVM的優(yōu)化
JVM的調(diào)優(yōu),盡量的避免FULL GC栓霜。
-
JVM堆配置參數(shù)
- -Xms初始堆大小
默認(rèn)物理內(nèi)存的1/64(<1GB) - -Xmx最大堆大小
默認(rèn)物理內(nèi)存的1/4(<1GB)翠桦,實(shí)際建議不大于4GB - 一般建議設(shè)置 -Xmx = -Xms
好處是避免每次 在gc之后,調(diào)整堆的大小叙淌,減少系統(tǒng)內(nèi)存分配開(kāi)銷秤掌。
- 整個(gè)堆的大小=年輕代大小+年老代大小+持久代大小
- -Xms初始堆大小
-
GC性能指標(biāo)
- 吞吐量 應(yīng)用花在非GC上的時(shí)間百分比
- GC負(fù)荷: 與吞吐量相反,指應(yīng)用花在GC上的時(shí)間百分比
- 暫停時(shí)間: 應(yīng)用花在GC stop-the-world的時(shí)間
- GC頻率: GC頻率
- 反應(yīng)速度:從一個(gè)對(duì)象成為垃圾到被回收的時(shí)間
- 一個(gè)交互式的應(yīng)用要求暫停時(shí)間越少越好鹰霍,然而闻鉴,一個(gè)非交互型的應(yīng)用需要GC負(fù)荷越低越好
- 一個(gè)實(shí)時(shí)系統(tǒng)對(duì)暫停時(shí)間和GC負(fù)荷的要求,越低越好茂洒。
-
內(nèi)存容量配置原則
-
年輕代大小選擇
響應(yīng)時(shí)間優(yōu)先的應(yīng)用:盡可能設(shè)大孟岛,直到接近系統(tǒng)的最低響應(yīng)時(shí)間限制,(根據(jù)實(shí)際情況選擇)督勺,在此種情況下渠羞,年輕代收集發(fā)生的頻率是最小的,同時(shí)智哀,減少到達(dá)老年代的對(duì)象次询。
吞吐量?jī)?yōu)先的應(yīng)用: 盡可能的設(shè)置大,可能到達(dá)的Gbit的程度瓷叫。因?yàn)閷?duì)響應(yīng)時(shí)間沒(méi)有要求屯吊,垃圾收集可以并行進(jìn)行送巡,一般適合8CPU以上的應(yīng)用。
-
避免設(shè)置過(guò)小盒卸,當(dāng)新生代設(shè)置過(guò)小會(huì)導(dǎo)致:
- YGC次數(shù)更加頻繁
- 可能導(dǎo)致YGC對(duì)象直接進(jìn)入舊生代骗爆,如果此時(shí)舊生代滿了,會(huì)觸發(fā)FGC
-
- 年老代大小選擇
-
響應(yīng)時(shí)間優(yōu)先的應(yīng)用: 年老代使用并發(fā)收集器CMS蔽介,所以大小需要小心設(shè)置摘投,一般考慮并發(fā)會(huì)話率和會(huì)話持續(xù)時(shí)間等一些參數(shù)。如果堆設(shè)置小了虹蓄,可能會(huì)造成內(nèi)存碎片犀呼;高回收頻率和應(yīng)用暫停使用傳統(tǒng)標(biāo)記清除的方式;如果堆大了武花,則需要較長(zhǎng)的收集時(shí)間圆凰。優(yōu)化方案需要參考以下數(shù)據(jù)(通過(guò)GC log):
- 并發(fā)垃圾收集信息
- 持久代并發(fā)收集次數(shù)
- 傳統(tǒng)gc信息
- 年輕代和年老代回收上的時(shí)間比例
吞吐量?jī)?yōu)先的應(yīng)用:一般吞吐量?jī)?yōu)先的應(yīng)用都有一個(gè)很大的年輕代和一個(gè)較小的年老代杈帐,這樣可以盡可能回收掉大部分短期對(duì)象体箕,減少中期的對(duì)象,而年老代盡量存放長(zhǎng)期存活的對(duì)象挑童。
-
- CMS(并發(fā)標(biāo)記清除)回收器相關(guān)參數(shù)
- 標(biāo)記清除算法
同時(shí)是一個(gè)使用多線程并發(fā)回收的垃圾收集器 - -XX:ParallelCMSThreads
手工設(shè)定CMS的線程數(shù)量累铅,CMS默認(rèn)啟動(dòng)的線程數(shù)是(ParallelGCThreads+3)/4
- 標(biāo)記清除算法
- -XX:+UseConcMarkSweepGC開(kāi)啟
使用ParNew+CMS+Serial Old的收集器組合進(jìn)行內(nèi)存回收,Serial Old作為CMS出現(xiàn)“Concurrent Mode Failure”失敗后的后備收集器站叼。 - -XX:CMSInitiatingOccupancyFraction
設(shè)置CMS收集器在年老代空間被使用多少后觸發(fā)垃圾收集娃兽,默認(rèn)值是68%,僅在CMS收集器時(shí)有效尽楔,-XX:CMSInitiatingOccupancyFraction=70 - -XX:+UseCMSCompactAtFullCollection
由于CMS收集器會(huì)產(chǎn)生碎片投储,此參數(shù)設(shè)置在垃圾收集后是否需要一次內(nèi)存碎片整理過(guò)程,僅在使用CMS收集器時(shí)有效 - -XX:+CMSFullGCBeforeCompaction
設(shè)置CMS收集器在進(jìn)行若干次垃圾收集后再次進(jìn)行內(nèi)存碎片整理過(guò)程阔馋,通常與UseCMSCompactAtFullCollection參數(shù)一起使用 - -XX:CMSInitiatingPermOccupancyFraction
設(shè)置Perm Gen使用到達(dá)多少比率時(shí)觸發(fā)玛荞,默認(rèn)92%
http://blog.csdn.net/ning109314/article/details/10411495/#comments