概述
思考GC需要完成的3件事:
* 哪些內(nèi)存需要回收;
* 什么時間回收橙垢;
* 以什么方式回收描沟;
回顧第二章Java內(nèi)存運行時各個區(qū)域的劃分:
* 程序計數(shù)器涎显、虛擬機棧、本地方法棧中的內(nèi)存區(qū)域是私有的浅缸,棧幀隨方法的運行而進棧出棧赘来,每一個棧幀所需分配的內(nèi)存在類結(jié)構(gòu)確定時就是已知的,因此這幾個區(qū)域不需要考慮內(nèi)存的回收怔接;
* 對Java的堆和方法區(qū),因為是共用的內(nèi)存稀轨,只有在程序運行期間才知道創(chuàng)建哪些對象扼脐,內(nèi)存的分配和回收都是動態(tài)的,垃圾收集器關(guān)注的往往是這部分的內(nèi)存回收;
對象已死嗎瓦侮?
判斷對象是否存活的方法有以下兩種:
引用計數(shù)法
給對象添加一個引用計數(shù)器艰赞,每當(dāng)有一個地方引用它時計數(shù)器加一,引用失效就減一肚吏,當(dāng)計數(shù)器值為0時方妖,說明此對象不再被任何地方引用,可以被回收罚攀。
判斷失效簡單党觅、效率高,但是不被主流虛擬機使用坞生,主要原因是無法解決對象間的循環(huán)引用問題仔役;
可達性分析法
通過一系列的稱為“GC Roots”的對象開始向下搜索,走過的路徑稱為引用鏈(Reference Chain)是己,當(dāng)一個對象到GC Roots沒有任何引用鏈又兵,即不可達GC Roots時,則判定這個對象不可用卒废;
可達性分析圖
可作為GC Roots的對象有如下幾類:
* Java虛擬機棧中(棧幀中的本地變量表)引用的對象沛厨;
* 本地方法棧JNI中(Native方法)引用的對象;
* 方法區(qū)中引用靜態(tài)屬性的對象摔认;
* 方法區(qū)中引用常量屬性的對象逆皮;
再談引用
在JDK1.2之后,Java對引用的概念進行了擴充参袱,將引用分為了`強引用电谣、軟引用、弱引用抹蚀、虛引用`剿牺,這四種引用強度由強到弱。
* 強引用:類似Object obj = new Object()环壤;這類的引用晒来,只要強引用還存在,垃圾收集器就永遠不會回收掉被引用的對象郑现;
* 軟引用:代表一類有用但非必要的對象湃崩,對于軟引用所關(guān)聯(lián)的對象,在系統(tǒng)即將拋出內(nèi)存溢出異常之前這類對象會被列入回收范圍內(nèi)進行二次回收接箫。如果回收之后還是沒有足夠的內(nèi)存攒读,那么系統(tǒng)將拋出內(nèi)存溢出異常。JDK1.2之后提供了SoftReference類來實現(xiàn)軟引用辛友;
* 弱引用:代表一類非必需的對象薄扁,強度比軟引用還弱。這類引用所關(guān)聯(lián)的對象只能生存到下一次垃圾收集之前。當(dāng)垃圾收集器工作時泌辫,無論當(dāng)前內(nèi)存是否充足随夸,都會回收掉弱引用關(guān)聯(lián)的對象。JDK1.2之后提供了WeakReference類來實現(xiàn)弱引用震放;
* 虛引用:又稱為幽靈引用或幻影引用宾毒,是最弱的引用關(guān)系。一個對象是否有虛引用殿遂,對于對象的生存周期沒有任何影響诈铛,也無法通過虛引用來獲取對象實例。虛引用的存在只是為了對象在垃圾回收時收到一個系統(tǒng)通知墨礁。在JDK1.2之后提供了PhantomReference來實現(xiàn)虛引用幢竹;
生存還是死亡
要真正宣告一個對象的死亡,需要經(jīng)歷`兩次標(biāo)記`恩静。如果對象進行可達性分析后發(fā)現(xiàn)對象到GC Roots沒有引用鏈焕毫,此時進行第一次標(biāo)記。標(biāo)記之后需要進行篩選驶乾,篩選的條件是該對象是否有必要執(zhí)行finalize()方法邑飒,有兩種情況會被判斷為沒有必要執(zhí)行finalize()方法:
1. 該對象沒有覆蓋自帶的finalize()方法;
2. 該對象已經(jīng)執(zhí)行過finalize()方法级乐;
篩選后如果對象有必要執(zhí)行finalize()方法疙咸,則會把該對象放到一個F-Queue的隊列中,由一個虛擬機自動創(chuàng)建的风科、優(yōu)先級低的線程去執(zhí)行撒轮。虛擬機不會承諾等待finalize()方法執(zhí)行完成,稍后GC會對F-Queue中的對象進行第二次小規(guī)模標(biāo)記贼穆。若對象沒有在此之前在finalize()重新與GC Roots相關(guān)聯(lián)题山,則該對象幾乎已經(jīng)是死亡的狀態(tài)。
對象的finalize()方法不建議被調(diào)用扮惦,因為它的運行代價高臀蛛、不確定性高亲桦、無法保證各個對象的調(diào)用順序崖蜜。
回收方法區(qū)
永久代的垃圾回收包括兩部分:廢棄常量和無用的類。
1. 廢棄常量的判定條件:當(dāng)前系統(tǒng)沒有任何地方引用這個常量客峭。即沒有任何地方引用常量池中的常量豫领,也沒有其他地方引用該常量的字面量。
2. 無用的類的判定條件:
1. 該類所有的實例被回收舔琅,即堆中沒有該類的實例等恐;
2. 加載該類的ClassLoader已經(jīng)被回收;
3. 該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法通過反射訪問類中方法课蔬;
在大量使用反射囱稽、動態(tài)代理、CGLib等ByteCode框架二跋、動態(tài)生成Jsp及OSGI這類頻繁自定義ClassLoader的場景要求虛擬機具備類卸載功能战惊,已保證永久代不會內(nèi)存溢出。
垃圾收集算法
* 標(biāo)記-清除算法(Mark-Sweep):首先標(biāo)記出需要回收的對象(兩階段標(biāo)記)扎即,然后對標(biāo)記過的對象進行垃圾收集吞获。缺點是效率不高并且清理出的內(nèi)存有大量的內(nèi)存碎片,致使在對象分配時只能進行“空閑列表分配”谚鄙;
* 復(fù)制算法(Cppying):將可用內(nèi)存分為兩塊各拷,每次只使用一塊,當(dāng)這一塊用完了闷营,就將這塊內(nèi)存上還存活的對象復(fù)制到另一塊內(nèi)存上烤黍,然后回收掉當(dāng)前的內(nèi)存。優(yōu)點是實現(xiàn)簡單傻盟、運行高效蚊荣,這樣就可以使用“指針碰撞“來分配內(nèi)存;缺點是代價太大莫杈,每次要犧牲一半的空間互例。在HotSpot虛擬機中,考慮到大部分對象的生存時間都很短適合在`新生代`中使用筝闹,所以將內(nèi)存分為了一塊Eden和兩塊Survivor媳叨,默認(rèn)比例是8:1:1,每次只使用Eden和一塊Survivor关顷,這樣每次只有10%的空間被浪費糊秆,當(dāng)另一塊Survivor內(nèi)存沒有空間存放上一次新生代收集下來的存活對象時,需要通過`分配擔(dān)保機制`進入老年代议双;
* 標(biāo)記-整理算法(Mark-Compact):標(biāo)記過程和Mark-Sweep的過程一致痘番,標(biāo)記之后,讓所有存活的對象都向一端移動平痰,然后直接清理掉邊界以外的內(nèi)存汞舱,適用在`老年代`;
* 分代收集算法:根據(jù)內(nèi)存的不同的區(qū)域劃分使用不同的收集算法宗雇。 在新生代使用復(fù)制算法昂芜,在老年代使用標(biāo)記-清除或標(biāo)記-整理算法,是現(xiàn)代虛擬機通常采用的算法赔蒲;
HotSpot的算法實現(xiàn)
枚舉根節(jié)點
* 由于要確保在一致性的快照中進行可達性分析泌神,從而導(dǎo)致必須要停止所有的Java執(zhí)行線程(”Stop The World”)良漱;
* 在HotSpot虛擬機中通過一組OopMap的數(shù)據(jù)結(jié)構(gòu)知道在哪些位置存放著對象引用;
安全點
* HotSpot沒有必要為每條指令都生成一個OopMap欢际,會在特定的位置記錄這些信息母市,這些位置稱為安全點;
* 執(zhí)行線程并非在所有地方都能停下開始GC损趋,只有到達安全點才可以暫停窒篱;
* 安全點的選定是以”是否能讓程序長時間運行“為條件選定的,如方法跳轉(zhuǎn)舶沿、異常處理墙杯、循環(huán)結(jié)構(gòu)等;
* 還需要考慮如何在GC時讓所有的線程都能停在安全點:分為搶占式中斷和主動式中斷兩種括荡;
1. 搶占式中斷(Preemptive Suspension):GC發(fā)生時高镐,所有線程停頓,如果發(fā)現(xiàn)有線程不在安全點上畸冲,就恢復(fù)線程嫉髓,讓它運行到安全點。幾乎被棄用邑闲;
2. 主動式中斷(Voluntary Suspension):設(shè)置一個標(biāo)志算行,各個線程主動輪詢這個標(biāo)志,為true時就將線程掛起苫耸。輪詢標(biāo)志的地方是和安全點重合的州邢,另外再加上為創(chuàng)建對象需要分配內(nèi)存的地方;
安全區(qū)域
* 如果程序沒有為CPU分配時間(線程處于Sleep或Blocked)褪子,此時就需要安全區(qū)(Safe Region)量淌。安全區(qū)指在一段代碼片段中,對象的引用關(guān)系不會發(fā)生變化嫌褪,在這個區(qū)域的任何位置開始GC都是安全的呀枢,Safe Region是Safe Point的擴展;
* 當(dāng)線程執(zhí)行到Safe Region的代碼片段時笼痛,需要標(biāo)識自己進入了Safe Region裙秋,離開Safe Region時,要檢查是否完成了根節(jié)點的枚舉或者整個GC過程缨伊,如果完成了摘刑,那么線程就繼續(xù)執(zhí)行,否則就必須等到收到可以安全離開Safe Region的信號倘核;
垃圾收集器
* 垃圾收集算法是內(nèi)存回收的方法論泣侮,垃圾收集器是具體實現(xiàn)即彪;
* 基于JDK1.7Update14之后版本的HotSpot虛擬機包含的收集器如下(兩兩連線代表可以搭配使用):
常見的垃圾收集器
Serial收集器
Serial收集器
* 最基本紧唱、發(fā)展歷史悠久的收集器活尊,曾經(jīng)是JDK1.3.1之前的虛擬機新生代收集的唯一選擇;
* 是一個`單線程`(并非指的是一個收集線程漏益,而是會暫停索引工作線程)收集器蛹锰;
* 簡單高效,沒有線程切換的額外開銷绰疤,即使是現(xiàn)在依然是虛擬機運行在`Client模式`下的默認(rèn)新生代收集器铜犬;
ParNew收集器
ParNew收集器
* 是Serial收集器的`多線程`版本,其余行為(控制參數(shù)轻庆、收集算法癣猾、對象分配規(guī)則、回收策略等)都與Serial收集器一致余爆,二者共用了大量的代碼纷宇;
* ParNew收集器在單CPU的條件下絕對不會有比Serial收集器更好的效果,ParNew收集器需要額外的線程交互開銷蛾方,即使是使用兩個CPU都不能百分之百的超越Serial收集器像捶;
* 運行在`Server模式`下首選的`新生代`收集器;
* `并發(fā)`(Concurrent):指用戶線程與垃圾收集線程同時執(zhí)行桩砰,用戶線程在繼續(xù)執(zhí)行而垃圾收集程序運行在另外一個CPU上拓春;
* `并行`(Parallel):指多條垃圾收集線程并行工作,但此時用戶線程仍處于等待狀態(tài)亚隅;
Parallel Scavange收集器
* 使用復(fù)制算法的`多線程`新生代收集器硼莽,幾乎和ParNew收集器一樣;
* `關(guān)注點`不一致煮纵,Parallel Scavenge收集器更加關(guān)注的系統(tǒng)到達一個可控制的吞吐量沉删,而其他收集器(如CMS)關(guān)注的是如何縮短垃圾收集時用戶線程的停頓時間;
* 高吞吐量(吞吐量=代碼運行時間/(代碼運行時間+垃圾收集時間))可以高效率的利用CPU時間醉途,適合在`后臺運算而不需要太多交互的任務(wù)`矾瑰;
* 提供了兩個參數(shù)用于精確控制吞吐量:-XX:MaxGCPauseMillis設(shè)置最大垃圾收集停頓時間,-XX:GCTimeRatio設(shè)置吞吐量大邪妗殴穴;
* 最大停頓時間的縮短是以降低吞吐量和減小新生代內(nèi)存空間為代價的,吞吐量設(shè)置的值相當(dāng)于吞吐量的倒數(shù)货葬;
* 參數(shù)-XX:UserAdaptiveSizePolicy為開關(guān)采幌,打開后不需要設(shè)置新生代大小(-Xmn)、Eden與Survivor的比例(-XX:SurvivorRatio)震桶、晉升老年代對象大小(-XX:PretenureSizeThreshold)等細節(jié)參數(shù)休傍,虛擬機會根據(jù)監(jiān)控參數(shù)動態(tài)調(diào)節(jié)以提供最合適的停頓時間和吞吐量,這種調(diào)節(jié)方式稱為`自適應(yīng)調(diào)節(jié)策略`蹲姐,這種策略也是Parallel Scavenge和ParNew最大的區(qū)別之一磨取;
Serial Old收集器
Serial Old收集器
* Serial Old收集器是Serial收集器的老年代版本人柿,`單線程`,使用標(biāo)記-整理算法忙厌;
* 主要意義也是在于給`Client模式`下的虛擬機使用凫岖;
* 在`Server模式下有兩種用途`:一是JDK1.5以及之前的版本中與Parallel Scavenge收集器搭配使用,二是作為CMS收集器的后備預(yù)案逢净,在并發(fā)收集發(fā)生Concurrent Mode Failure時使用哥放;
Parallel Old收集器
Parellel Old收集器
* 是Parallel Scavenge的老年代收集器版本,使用`多線程`和標(biāo)記-整理算法爹土,JDK1.6之后開始提供甥雕;
* Parallel Scavenge收集器架構(gòu)中本身有PS MarkSweep收集器來進行老年代回收,`并非直接使用Serial Old收集器`胀茵;
* 老年代的Serial Old收集器在服務(wù)端應(yīng)用性能上的拖累犀农,即使使用了Parallel Scavenge收集器也未必能在整體應(yīng)用上獲得吞吐量最大化的效果,單線程的老年代收集中無法充分利用服務(wù)器多CPU的處理能力宰掉;
* 在`注重吞吐量以及CPU資源敏感的場合`呵哨,都可以優(yōu)先考慮Parallel Scavenge + Parallel Old收集起的組合;
CMS收集器
CMS收集器
* CMS(Concurrent Mark Sweep)是一種以獲取最短回收停頓時間為目標(biāo)的收集器轨奄;
* 目前很大一部分Java應(yīng)用集中在互聯(lián)網(wǎng)或者B/S系統(tǒng)的服務(wù)端孟害,這類應(yīng)用尤其`重視服務(wù)的響應(yīng)速度`,CMS很適合這種場景挪拟;
* 基于標(biāo)記-清除算法實現(xiàn)挨务,整個過程分為`4個步驟`:
1. 初始標(biāo)記(CMS Initial Marking):需要Stop The World,僅僅是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象玉组,速度很快谎柄;
2. 并發(fā)標(biāo)記(CMS Concurrent Mark):是從GC Roots開始對堆中對象進行可達性分析,耗時較長惯雳,但可同時與用戶線程并發(fā)執(zhí)行朝巫;
3. 重新標(biāo)記(CMS Remark):需要Stop The World,是對并發(fā)標(biāo)記階段因用戶線程執(zhí)行導(dǎo)致標(biāo)記發(fā)生改變的那部分對象的修正石景;
4. 并發(fā)清除(CMS Concurrent Sweep):執(zhí)行垃圾回收劈猿;
* `優(yōu)點`是能并發(fā)的和用戶線程一起執(zhí)行,停頓時間短潮孽;
* 3個明顯的`缺點`:
1. `對CPU資源比較敏感`揪荣。由于CMS收集器占用了一部分CPU資源而導(dǎo)致應(yīng)用程序變慢,總吞吐量會降低往史。CMS默認(rèn)開啟的線程數(shù)是(CPU數(shù)量+3)/4仗颈,隨著CPU數(shù)量的下降對程序的影響就越明顯,為了減小這種影響產(chǎn)生了產(chǎn)生了“增量式并發(fā)收集器”的CMS收集器變種椎例,主要目的就是在“Stop The World”期間挨决,讓GC線程和用戶線程交替運行请祖,避免GC線程獨占資源是時間,從而使下降速度不那么明顯凰棉,效果一般损拢;
2. `無法處理浮動垃圾`陌粹。因為在CMS收集器執(zhí)行的過程中撒犀,不斷有用戶線程運行,CMS在當(dāng)次無法回收掉掏秩,只能留在下次或舞,即CMS在運行期間需要有內(nèi)存空間支持用戶線程繼續(xù)運行∶苫茫可以通過調(diào)高參數(shù)-XX:CMSInitiatingOccupancyFraction的值來提高觸發(fā)百分比從而降低內(nèi)存回收次數(shù)映凳,獲得更好的性能。在CMS運行期間沒有足夠的內(nèi)存滿足程序需要邮破,就會出現(xiàn)Concurrent Mode Failure诈豌,此時會啟動`后備預(yù)案`,臨時啟動Serial Old收集器重新進行老年代的垃圾收集抒和,停頓時間更加漫長矫渔。所以參數(shù)-XX:CMSInitiatingOccupancyFraction設(shè)置的太高容易造成Concurrent Mode Failure,性能反而降低摧莽;
3. `產(chǎn)生大量內(nèi)存碎片`庙洼。因為CMS是基于標(biāo)記-清除實現(xiàn)的,所以無可避免的會在收集之后產(chǎn)生大量的內(nèi)存碎片镊辕,碎片過多時油够,將會給大對象的分配造成很大的問題。CMS提供了一個參數(shù)-XX:+UseCMSCompactAtFullCollection開關(guān)參數(shù)(默認(rèn)開啟)征懈,用于在CMS將要FullGC時開啟內(nèi)存碎片的合并整理過程石咬,該過程無法并發(fā),停頓時間較長卖哎。另外一個參數(shù)-XX:CMSFullGCsBeforeCompaction用于設(shè)置執(zhí)行過多少次FullGC后進行一次壓縮整理(默認(rèn)值為0)碌补;
G1收集器
G1收集器
* 一款面向`服務(wù)端`應(yīng)用的垃圾收集器,使命是替換掉CMS棉饶;
* `特點`:
1. 并行與并發(fā)(可以充分利用多個CPU來降低Stop The World的停頓時間)厦章;
2. 分代收集(可獨立管理整個堆,但對不同年齡的對象使用不同的策略)照藻;
3. 空間整合(整體上采用了標(biāo)記-整理算法袜啃,局部采用了復(fù)制算法);
4. 可預(yù)測的停頓(將堆分為大小相等的獨立區(qū)域幸缕,避免全區(qū)域的垃圾收集)群发;
* 關(guān)于`Region`:G1收集器中晰韵,雖然新生代和老年代的概念還在,但新生代和老年代不再是物理隔離的了熟妓,他們都是部分Region的集合雪猪。G1跟蹤各個Region的垃圾堆積的價值大小(回收所獲得空間的大小以及回收所需時間的經(jīng)驗值),在后臺維護一個優(yōu)先列表起愈,每次根據(jù)允許的收集時間只恨,優(yōu)先回收價值最大的Region;
* 不同Region之間的對象引用或新生代和老年代對象的相互引用抬虽,虛擬機都是采用`Remembered Set`來避免全堆掃描的官觅。虛擬機發(fā)現(xiàn)程序在對Reference類型的數(shù)據(jù)進行寫操作時,會產(chǎn)生一個Write Barrier暫時中斷操作阐污,檢查Reference引用的對象是否處于不同的Region(或新生代引用了老年代的對象)休涤,如果是,便通過CardTable把相關(guān)信息寫入到被引用對象所屬Region中的Remembered Set中笛辟。進行GC時功氨,把Remembered Set加入GC Roots枚舉從而避免全堆掃描;
* 分為`4個步驟`:
1. 初始標(biāo)記(Initial Marking):僅僅是標(biāo)記GC Roots能直接關(guān)聯(lián)到的對象手幢,并且修改TAMS(Next Top at Mark Start)的值捷凄,讓下一階段的用戶線程運行時能正常的創(chuàng)建對象,這階段的線程停頓時間很短弯菊;
2. 并發(fā)標(biāo)記(Concurrent Mark):是從GC Roots開始向下進行可達性分析纵势,找出存活的對象,耗時較長管钳,但這個階段用戶線程可與垃圾收集線程并發(fā)執(zhí)行钦铁;
3. 最終標(biāo)記(Final Marking):這個階段是為了修正上一個階段由于用戶線程運行導(dǎo)致對象標(biāo)記發(fā)生變化的那部分標(biāo)記記錄,虛擬機將這段時間對象的變化記錄在線程Remembered Set Logs中才漆,最終標(biāo)記階段需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Set中牛曹,這個階段需要停止線程,但可并行執(zhí)行醇滥;
4. 篩選回收(Live Data Counting and Evacuation):首先對各個Region的回收價值和成本進行排序黎比,根據(jù)用戶期望的GC停頓時間來制定回收計劃,這個階段也可以做到和用戶線程一起并發(fā)執(zhí)行鸳玩,因為只回收一部分Region阅虫,時間是用戶可控制的,停頓用戶線程將大幅提高收集效率不跟;
理解GC日志
GC日志示例
* 最前面的數(shù)字代表GC發(fā)生的時間(虛擬機啟動以來經(jīng)過的秒數(shù))颓帝;
* “[GC”和“[Full GC”說明停頓類型,有Full代表的是Stop-The-World的;
* “[DefNew”购城、“[Tenured”和“[Perm”表示GC發(fā)生的區(qū)域吕座;
* 方括號內(nèi)部的“3324K -> 152K(3712K)” 含義是 “GC前該內(nèi)存已使用容量 -> GC后該內(nèi)存區(qū)域已使用容量(該區(qū)域總?cè)萘?”;
* 方括號之外的“3324K -> 152K(11904)” 含義是 “GC前Java堆已使用容量 -> GC后Java堆已使用容量(Java堆總?cè)萘?”瘪板;
* 再往后“0.0025925 secs”表示該內(nèi)存區(qū)域GC所占用的時間吴趴;
垃圾收集器參數(shù)總結(jié)
常用收集參數(shù)1
常用手機參數(shù)2
內(nèi)存分配與回收策略
自動內(nèi)存管理最終可以歸結(jié)為自動化地解決了兩個問題:對象的內(nèi)存分配和回收為對象分配的內(nèi)存。對象的分配`主要在堆上`進行侮攀,但也可能是經(jīng)過JIT編譯后被拆散為標(biāo)量類型`間接地在棧上`分配锣枝。
* 對象`優(yōu)先在新生代的Eden分配`:當(dāng)Eden區(qū)沒有足夠的空間進行分配時,虛擬機會發(fā)生一次Minor GC魏身,若對象都還存活且Survivor區(qū)沒有足夠的空間時則只能通過分配擔(dān)保機制提前將對象轉(zhuǎn)移到老年區(qū)惊橱;
1. Minor GC(新生代GC):發(fā)生在新生代的垃圾收集動作蚪腐,Minor GC發(fā)生十分頻繁箭昵,回收速度也比較快;
2. Major GC/Full GC(老年代GC):發(fā)生在老年代的垃圾收集動作回季,Major GC的出現(xiàn)經(jīng)常會伴隨著至少一次的Minor GC家制,但非絕對。Major GC的速度一般會比Minor GC慢十倍以上泡一;
* `大對象直接進入老年代`(典型的大對象是很長的字符串或數(shù)組):code中應(yīng)盡量避免生命周期很短的大對象颤殴,經(jīng)常出現(xiàn)大對象容易導(dǎo)致內(nèi)存還有很多空間是就提前觸發(fā)垃圾收集以獲取足夠的連續(xù)空間來分配他們。參數(shù)-XX:PretenureSizeThreshold使大于這個值的對象直接進入老年代分配鼻忠,避免在Eden和Survivor頻繁進行復(fù)制涵但,這個參數(shù)只對Serial收集器和ParNew收集器有效,Parallel Scavenge收集器并不需要設(shè)置帖蔓,如果必須有場景要使用這個參數(shù)矮瘟,可以考慮ParNew + CMS的組合;
* `長期存活的對象將進入老年代`:虛擬機為每一個對象定義了一個對象年齡計數(shù)器塑娇,從Eden出生經(jīng)過Minor GC后仍存活澈侠,并能被Survivor容納移動到Survivor空間中,年齡+1埋酬;可通過參數(shù)-XX:MaxTenuringThreshold設(shè)置對象晉升到老年代的年齡閾值哨啃;
* `動態(tài)對象年齡判定`:如果在Survivor區(qū)的所有同一年齡的對象所占的空間達到了Survivor區(qū)的一半時,大于等于該年齡的對象可以直接進入老年代写妥;
* `空間分配擔(dān)保`:在發(fā)生Minor GC之前拳球,虛擬機會首先檢查老年代的最大可用連續(xù)空間是否大于新生代中所有對象的總空間。若大于珍特,則此次Minor GC是安全的祝峻,否則虛擬機會檢查HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗,如果允許則繼續(xù)檢查老年代的最大可用連續(xù)空間是否大于歷次晉升到老年代對象的平均大小,如果大于則嘗試進行一次Minor GC呼猪,這時的Minor GC是有風(fēng)險的画畅;如果小于或者HandlePromotionFailure設(shè)置值不允許擔(dān)保失敗,則老年代也會進行一次Full GC宋距,JDK1.6 Update 24之后的規(guī)則變?yōu)橹灰夏甏倪B續(xù)空間大于新生代所有的對象的總大小或者歷次晉升到老年代的對象的平均大小就會進行Minor GC轴踱,否則執(zhí)行Full GC;
總結(jié)
總結(jié)