1.垃圾如何確認
對于大多數(shù)語言中判斷對象是否存活會采用引用計數(shù)法:給對象添加一個引用計數(shù)器,當有一個地方引用時痒留,計數(shù)器就加1,當引用失效時蠢沿,計數(shù)器就減1伸头。任何時刻只要計數(shù)器為0則回收。但是這種算法無法解決對象之間互相循環(huán)引用的問題舷蟀。如A引用B,而B又引用A恤磷,計數(shù)器永遠不為0,這兩個對象再也無任何引用野宜。這樣GC不能回收這兩個對象扫步。
因此,在JAVA中匈子,采用了可達性分析算法來解決這個問題河胎,判斷對象是否存活。
可達性分析算法:通過GCRoots的對象作為起點虎敦,從這些節(jié)點向下搜索游岳,搜索走過的路徑稱之為引用鏈(Reference Chain),當一個對象到達GCRoots沒有任何鏈相連其徙,則證明此對象不可用胚迫,可以被GC回收。
上圖藍色部分將會被GC回收擂橘。
2.垃圾收集算法
2.1 標記-清除算法
標記-清除算法是最基礎的垃圾收集算法晌区。分為標記和清除兩個階段:
首先標記出需要回收的對象,在標記完成后統(tǒng)一回收所有被標記的對象。
存在的問題: 一是效率低朗若,標記和清除兩個過程效率都不高恼五。二是空間問題,標記清除后會產生大量的不連續(xù)的內存碎片哭懈≡致空間碎片太多會導致程序在運行過程中需要分配較大對象時無法找到連續(xù)內存而不得不提前觸發(fā)GC。
2.2復制算法
為了解決效率問題遣总,復制算法應運而生睬罗。它將可用內存分為大小相等的兩塊,每次只使用其中一塊旭斥,當其中一塊內存耗盡容达,觸發(fā)GC時就將還存在的對象復制到另外一塊內存上面,然后再把已使用過的內存空間一次性清除垂券。這樣實現(xiàn)了對整個半區(qū)的GC花盐,內存分配時完全不用考慮碎片的情況。缺點在于這種算法將內存的可用大小縮小了一半菇爪。
2.3 標記-整理算法
復制算法當對象存活率較高的情況時算芯,照樣會出現(xiàn)效率低下的問題,另外內存要浪費50%凳宙。為了避免上述問題熙揍,出現(xiàn)了 標記-整理算法。(mark-compact) 其標記過程與標記-清除算法一樣氏涩,但后續(xù)步驟不直接清除届囚,而是讓所有存活的對象都向一端移動,然后直接清理掉邊界以外的內存削葱。
2.4分代收集法
根據對象的存活周期將內存分為幾塊奖亚,如當前hotsport就分為新生代和老年代淳梦,然后在各個年代采用不同的收集算法析砸。新生代采用復制算法,老年代采用標記清除或者標記整理算法爆袍。
3.垃圾收集器
垃圾收集器是內存回收算法的具體實現(xiàn)首繁。不同的廠商不同版本的虛擬機對垃圾收集器的實現(xiàn)有很大差別。在HotSport虛擬機1.7版本中陨囊,所有垃圾收集器如下圖所示:
3.1 Serial收集器
Serial收集器是一個單線程收集器弦疮,只會使用一條線程去收集,同時需要暫停其他所有工作線程蜘醋,直至收集結束。
優(yōu)點:
簡單高效,在單CPU環(huán)境中沒有線程開銷熙侍,可以獲得最大的效率。
適用于運行在Client模式下的虛擬機编检。
3.2 ParNew收集器
ParNew收集器是Serial收集器的多線程版本,除了多線程收集之外扰才,其余包括控制參數(shù)允懂、收集算法、對象分配規(guī)則衩匣、回收策略等都與Serial收集器一樣蕾总。
ParNew收集器是jvmServer模式下的首選新生代收集器,除Serial收集器外琅捏,只有ParNew收集器能與CMS收集器配合工作生百。默認開啟的收集線程數(shù)與CPU的數(shù)量相同”樱可以通過 -XX:parallelGCThreads參數(shù)來限制垃圾收集的線程數(shù)置侍。
3.3 Parallel Scavenge收集器
Parallel Scavenge收集器是一個新生代收集器,也采用復制算法拦焚,并行多線程收集蜡坊。特點在于達到一個可控目標吞吐量(Throughput)。
吞吐量 = 運行用戶代碼的時間/(運行用戶代碼的時間+GC耗時)赎败。
-XX:MaxGCPauseMillis 設置停頓時間秕衙。
-XX:GCTimeratio 設置吞吐量。
Parallel Scavenge收集器 能夠根據上述兩個參數(shù)進行自適應調節(jié)僵刮。
3.4 Serial Old收集器
Serial Old收集器是Serial收集器的老年代版本据忘,同樣式一個單線程收集器,使用標記整理算法搞糕。收集器的主要意義也是提供給Client模式下使用勇吊,在Server模式下,主要有兩大用途:
3.5 Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本窍仰,使用多線程的標記整理算法汉规。
在注重吞吐量以及CPU資源敏感的場合,優(yōu)先考慮Parallel Scavenge和Parallel Old的組合進行收集驹吮。
3.6 CMS 收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲得最短回收停頓時間為目標的收集器针史。主要應用在互聯(lián)網或BS系統(tǒng)的服務器上,這類應用尤其重視服務器的響應速度碟狞,希望停頓時間最短啄枕,以給用戶最好的體驗。
CMS時基于標記清除算法實現(xiàn)的族沃,主要分為4個步驟:
初始標記(CMS initial mark):標記GC Roots能直接關聯(lián)到的對象频祝,速度很快泌参。
并發(fā)標記(CMS concurrent mark):進行roots tracing過程。
重新標記(CMS remark):修正并發(fā)標記階段因用戶程序繼續(xù)運作而導致標記產生變動的哪一部分對象的標記記錄常空,這個極端停頓時間比初始標記長及舍。但遠比并發(fā)標記短。
并發(fā)清除(CMS concurrent sweep):回收資源窟绷。
上述步驟中锯玛,初始標記、重新標記這兩個步驟需要停止所有線程兼蜈。
CMS收集器缺點:
CMS收集器對CPU資源非常敏感攘残,在CPU資源很匱乏時,效率會非常滴为狸,造成停頓時間過長歼郭。
CMS收集器無法處理浮動垃圾,即在CMS收集器收集過程中新產生的垃圾辐棒,如果浮動垃圾較大病曾,會導致CMS失敗。當CMS失敗后漾根,會啟動后背預案泰涂,臨時啟用SerialOld收集器來進行老年代收集。這樣停頓時間就會比較長辐怕。
CMS收集器基于標記清除算法逼蒙,會產生大量的內存碎片,需要額外開啟內存整理寄疏。通過參數(shù) -XX:CMSFullGCsBeforeCompation是牢,設置執(zhí)行多少次不壓縮的GC后進行一次壓縮。
3.7 G1收集器
G1是一款面向服務端的垃圾收集器陕截,具有如下特點:
并行與并發(fā):G1能充分利用多CPU驳棱,多環(huán)境下的硬件優(yōu)勢,使用多個CPU來縮短停頓時間农曲,部分其他收集器需要停頓的動作社搅,G1中可以并發(fā)的方式進行執(zhí)行。
分代收集:G1中仍然使用分代收集朋蔫。
空間整合:G1基于標記整理算法實現(xiàn)收集罚渐,局部來看是基于復制算法却汉,運行期間不會產生內存碎片驯妄。
可預測停頓:可以指定停頓的時間片段。
G1可分為如下步驟:
初始標記(Initial marking)
并發(fā)標記(Concurrent marking)
最終標記(Final Marking)
篩選回收(Live Data Counting and evacuation)
4.垃圾回收器參數(shù)總結
參數(shù) | 描述 |
---|---|
UserSerialGC | 虛擬機在client模式下的默認值合砂,打開此開關后青扔,用于Serial+Serial Old的收集器組合進行內存回收 |
UserParNewGC | 打開此開關 使用ParNew + Serial Old收集器組合進行內存回收 |
UseConcMarkSweepGC | 打開此開關源织,使用ParNew+CMS+Serial Old收集器組合進行內存回收。Serial Old在CMS收集器出現(xiàn)concurrent Mode Failure 失敗后的后備收集器 |
UseParallelGC | 在server模式下的默認值微猖,打開此開關后使用Scavenge+Serial Old收集器組合進行回收 |
UseParallelOldGC | 打開此開關后使用 Parallel Scavenge+Parallel Old收集器組合進行內存回收 |
SurvivorRatio | 新生代中Eden區(qū)域與Survivor區(qū)域的比值谈息,默認為8,表示Eden:Survivor=8:1 |
PretenureSizeThreshold | 直接晉升到老年代對象的大小凛剥,設置這個參數(shù)后大于這個參數(shù)的對象直接在老年代中分配 |
MaxTenuringThreshold | 晉升老年代對象的年齡,每個對象堅持一次MnorGC年齡就加一侠仇,當超過這個參數(shù)值就進入老年代 |
UseAdaptiveSizePolicy | 動態(tài)調整java堆各個區(qū)域的大小以及進入老年代的年齡 |
HandlePromotionFailure | 是否允許分配擔保失敗,即老年代剩余空間不足以應付新生代整個對象都存活的特殊情況 |
ParalleGCThreads | 設置并行GC時進行內存回收的線程數(shù) |
GCTimeratio | GC時間占總時間比率犁珠,默認值為99逻炊,允許1%的GC時間。只在Parallel Seavenge收集器時生效 |
MaxGCPauseMillis | 設置GC的最大停頓時間犁享,只在Parallel Seavenge收集器時生效 |
CMSInitiatingOccupancyFration | 設置CMS老年代空間被使用多少后觸發(fā)GC余素,默認值為68%,只在CMS收集器時生效 |
UseCMSCompactAtFullCollection | 設置CMS收集器完成垃圾收集后是否需要進行一次碎片整理炊昆,只在CMS垃圾收集器時生效 |
CMSFullGCBeforeCompaction | 設置CMS收集器進行若干次垃圾收集后再啟動一次內存碎片整理桨吊,只在CMS垃圾收集器時生效 |
5. 內存分配與回收策略
MinorGC:新生代發(fā)生的垃圾回收動作,一般速度比較快凤巨。
MajorGC/FullGC:發(fā)生在老年代的GC视乐,出現(xiàn)MajorGC,經常會伴隨一次MinorGC敢茁。MajorGC速度一般比MinorGC慢10倍以上炊林。
1.大多數(shù)情況下,對象在Eden區(qū)中進行分配卷要,當Eden中沒有足夠的分配空間時渣聚,虛擬機將進行一次MinorGC。
2.大對象直接進入老年代僧叉,避免觸發(fā)大量內存復制奕枝。
3.長期存活的對象進入老年代。
4.動態(tài)對象年齡判定瓶堕,為了能更好的適應不同的程序的內存狀況隘道,虛擬機并不是永遠需要要求對象的年齡達到MaxTenuringThreshold才能晉升老年代。如果在Survivor空間中相同年齡對象的大小總和大于Surrvivor空間的一半郎笆,則年齡大于等于該年齡的對象就可以直接進入老年代谭梗。
5.空間分配擔保:在發(fā)送MinorGC之前虛擬機會先檢查老年代最大可用的連續(xù)內存空間是否大于新生代所有對象的總和,如果條件成了宛蚓,則MinorGC可以確保安全激捏。如果不成立,則會檢查是否設置了允許擔保失敗凄吏,如果允許远舅,則會繼續(xù)檢查老年代最大可用連續(xù)內存空間是否大于歷次晉升到老年代對象的平均大小闰蛔,如果大于,將嘗試進行一次MinorGC图柏,如果小于序六,則要進行一次FullGC。