前言
如果本篇文章有錯,歡迎各路大神瘋狂diss~~當(dāng)然嘍宛徊,如果你看了這篇文章有所收獲佛嬉,那就瘋狂點(diǎn)贊吧逻澳,你的點(diǎn)贊就是對我的最大鼓勵∨唬可以順便加個關(guān)注哦斜做,回家不迷路,不定期更新博客~~
周志明那本《深入理解 JAVA 虛擬機(jī)》翻了一遍又一遍湾揽,終于鼓起勇氣在這里寫下關(guān)于 JVM 的博客H勘啤!库物!現(xiàn)在霸旗,我要開始把我所理解到的記錄在這里,和各位朋友一起分享F萁摇S崭妗!
我相信點(diǎn)開這篇文章的小伙伴一定知道JVM是啥了吧民晒?What精居,還不知道?好吧潜必,看看維基我想你應(yīng)該就會明白了:Java虛擬機(jī)- 維基百科靴姿,自由的百科全書
不過,作為一個愛思考的在校大學(xué)生刮便,我也總結(jié)了以下三點(diǎn):
- 一個能夠運(yùn)行字節(jié)碼的虛擬機(jī)空猜。
- 屏蔽了具體的操作系統(tǒng)的信息。
- 正是以上兩點(diǎn)恨旱,使得Java程序具有一次編譯辈毯,到處執(zhí)行的特性。
關(guān)于JVM是什么的介紹就到這里搜贤,還是老樣子谆沃,先來看看這篇文章的結(jié)構(gòu):
運(yùn)行時數(shù)據(jù)區(qū)域
什么是運(yùn)行時數(shù)據(jù)區(qū)域?
Java程序在運(yùn)行時仪芒,會為JVM單獨(dú)劃出一塊內(nèi)存區(qū)域唁影,而這塊內(nèi)存區(qū)域又可以再次劃分出一塊運(yùn)行時數(shù)據(jù)區(qū),運(yùn)行時數(shù)據(jù)區(qū)域大致可以分為五個部分:
從上面的圖中掂名,有兩種顏色不同的區(qū)域据沈,紅色的是線程共享區(qū)域,綠色的是線程私有區(qū)域饺蔑。下面我們一個一個講清楚锌介,不過在學(xué)習(xí)這部分的時候,最好先思考為什么會有這些區(qū)域。難道是因為存在即合理孔祸?
堆(Heap)
很多做開發(fā)的同學(xué)隆敢,會格外關(guān)注堆和棧,這是不是就從另一個角度說明了堆和棧的重要性崔慧?既然如此拂蝎,我們就從同學(xué)們關(guān)注的點(diǎn)開始說。(貼心吧惶室,是不是感覺眼角再一次被打濕温自?)
先把干貨放上來,首先拇涤,Java堆區(qū)具有下面幾個特點(diǎn):
- 存儲的是我們new來的對象捣作,不存放基本類型和對象引用。
- 由于創(chuàng)建了大量的對象鹅士,垃圾回收器主要工作在這塊區(qū)域券躁。
- 線程共享區(qū)域,因此是線程不安全的掉盅。
- 能夠發(fā)生內(nèi)存溢出也拜,主要有OutOfMemoryError和StackOverflowError。
那么什么時候發(fā)生OutOfMemoryError趾痘,什么時候發(fā)生StackOverflowError慢哈?虛擬機(jī)在擴(kuò)展棧時無法申請到足夠的內(nèi)存空間,將拋出OutOfMemoryError異常永票,線程請求的棧深度超過虛擬機(jī)所允許的最大深度卵贱,將拋出StackOverflowError異常。
其實(shí)侣集,Java堆區(qū)還可以劃分為新生代和老年代键俱,新生代又可以進(jìn)一步劃分為Eden區(qū)、Survivor 1區(qū)世分、Survivor 2區(qū)编振。具體比例參數(shù)的話,可以看一下下面這張圖臭埋。
我想圖中已經(jīng)解釋相當(dāng)清楚了踪央,就沒有必要文字說明了吧?關(guān)于Java堆對象的創(chuàng)建瓢阴,以及何時會發(fā)生內(nèi)存泄漏畅蹂,我后面應(yīng)該會專門寫一篇文章,這里的話就只是一些理論介紹荣恐。
虛擬機(jī)棧(VM Stack)
Java虛擬機(jī)棧也是一塊被開發(fā)者重點(diǎn)關(guān)注的地方魁莉,同樣,先把干貨放上來:
- 線程私有區(qū)域,每一個線程都有獨(dú)享一個虛擬機(jī)棧旗唁,因此這是線程安全的區(qū)域。
- 存放基本數(shù)據(jù)類型以及對象的引用痹束。
- 每一個方法執(zhí)行的時候會在虛擬機(jī)棧中創(chuàng)建一個相應(yīng)棧幀检疫,方法執(zhí)行完畢后該棧幀就會被銷毀。方法棧幀是以先進(jìn)后出的方式虛擬機(jī)棧的祷嘶。
- 每一個棧幀又可以劃分為局部變量表屎媳、操作數(shù)棧、動態(tài)鏈接论巍、方法出口以及額外的附加信息烛谊。
- 這個區(qū)域可能有兩種異常:如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常(通常是遞歸導(dǎo)致的)嘉汰;JVM動態(tài)擴(kuò)展時無法申請到足夠內(nèi)存則拋出OutOfMemoryError異常丹禀。
同樣,這篇文章反響好的話鞋怀,實(shí)戰(zhàn)練習(xí)后面單獨(dú)出文章双泪。
本地方法棧(Native Method Stack)
本地方法棧其實(shí)可以和Java虛擬機(jī)棧進(jìn)行對比理解,唯一不同的是本地方法棧是Java程序在調(diào)用本地方法的時候創(chuàng)建棧幀的地方密似。和JVM棧一樣焙矛,這個區(qū)域也會拋出StackOverflowError和OutOfMemoryError。
方法區(qū)(Method Area)
方法區(qū)残腌,也應(yīng)該是以一塊被重點(diǎn)關(guān)注的區(qū)域村斟。同樣,方法區(qū)的主要特點(diǎn)如下:
- 線程共享區(qū)域抛猫,因此這是線程不安全的區(qū)域蟆盹。
- 方法區(qū)也是一個可能會發(fā)生OutOfMemoryError的區(qū)域。
- 方法區(qū)存儲的是從Class文件加載進(jìn)來的靜態(tài)變量邑滨、類信息日缨、常量池以及編譯器編譯后的代碼。
對于方法區(qū)掖看,我覺得重點(diǎn)應(yīng)該說一下常量池匣距。常量池可以分為Class文件常量池以及運(yùn)行時常量池,Java程序運(yùn)行后哎壳,Class文件中的信息被字節(jié)碼執(zhí)行引擎加載到了方法區(qū)毅待,從而形成了運(yùn)行時常量池。
另外归榕,說起方法區(qū)尸红,可能還有人會把它與永久代、元空間混為一談。那么他們之間的區(qū)別到底是什么外里?方法區(qū)是Java虛擬機(jī)規(guī)范中的定義怎爵,是一種規(guī)范,而永久代是一種實(shí)現(xiàn)盅蝗,一個是標(biāo)準(zhǔn)一個是實(shí)現(xiàn)鳖链。不過Java 8以后就沒有永久代這個說法了,元空間取代了永久代墩莫。
程序計數(shù)器(Program Counter Register)
程序計數(shù)器非常簡單芙委,想必大家都不是Java的初學(xué)者了,也都應(yīng)該明白一點(diǎn)線程與進(jìn)程的概念狂秦?(靈魂拷問灌侣,你明白么?)不明白沒關(guān)系裂问,我一句話給你講清楚侧啼。
進(jìn)程是資源分配的最小單位纵顾,線程是CPU調(diào)度的最小單位调缨,一個進(jìn)程可以包含多個線程, Java線程通過搶占的方法獲得CPU的執(zhí)行權(quán)∨副酰現(xiàn)在可以思考下面這個場景戴甩。
某一次符喝,線程A獲得CPU的執(zhí)行權(quán),開始執(zhí)行內(nèi)部程序甜孤。但是線程A的程序還沒有執(zhí)行完协饲,在某一時刻CPU的執(zhí)行權(quán)被另一個線程B搶走了。后來經(jīng)過線程A的不懈努力缴川,又搶回了CPU的執(zhí)行權(quán)茉稠,那么線程A的程序又要從頭開始執(zhí)行?
這個時候程序計數(shù)器就粉墨登場了把夸,它的作用就是記錄當(dāng)前線程所執(zhí)行的位置而线。 這樣,當(dāng)線程重新獲得CPU的執(zhí)行權(quán)的時候恋日,就直接從記錄的位置開始執(zhí)行膀篮,分支、循環(huán)岂膳、跳轉(zhuǎn)誓竿、異常處理也都依賴這個程序計數(shù)器來完成。此外谈截,程序計數(shù)器還具有以下特點(diǎn):
- 線程私有筷屡,每一個線程都有一個程序計數(shù)器涧偷,因此它是線程安全的。
- 唯一一塊不存在OutOfMemoryError的區(qū)域毙死,可能是設(shè)計者覺得沒必要燎潮。
對象的創(chuàng)建與訪問
對象的創(chuàng)建
前面我們已經(jīng)說過,對象是在堆中創(chuàng)建的扼倘,通常只需要new一個就行了跟啤。難道就是這么簡單?確實(shí)沒有這么簡單唉锌,就單單是這樣的new關(guān)鍵字,Java虛擬內(nèi)部進(jìn)行了一系列的sao操作竿奏。
當(dāng)虛擬機(jī)遇到字節(jié)碼new指令時袄简,就會去運(yùn)行時常量池尋找該實(shí)例化對象相對應(yīng)的類是否被加載、解析和初始化泛啸。如果沒有被加載绿语,就會先加載該類的信息,否則就為新生對象分配內(nèi)存候址。
分配內(nèi)存無非有兩種方法:
- 指針碰撞:通過一個類似于指針的東西為對象分配內(nèi)存吕粹,前提是堆空間是相對規(guī)整的。
- 空閑列表:堆空間不規(guī)整岗仑,使用一個列表記錄了哪些空間是空閑的匹耕,分配內(nèi)存的時候會更新列表。
以上是兩種不同的方法荠雕,至于虛擬機(jī)使用哪一種方法稳其,這個就取決虛擬機(jī)的類型了。
對象的內(nèi)存布局
對象在堆中的存儲布局可以分為三個部分:
-
對象頭
- 第一類信息:存儲對象自身的運(yùn)行時數(shù)據(jù)炸卑,例如哈希碼既鞠、GC分代年齡、鎖狀態(tài)標(biāo)志等等盖文。
- 第二類信息:指針類型嘱蛋,Java虛擬機(jī)通過這個指針來確定該對象是那個類的實(shí)例。
-
實(shí)例數(shù)據(jù):對象真正存儲的有效信息五续。
-
對齊填充:沒有實(shí)際的意義洒敏,起著占位符的作用。
對象的訪問定位
我們前面說到過返帕,Java虛擬機(jī)棧中存儲的是基本數(shù)據(jù)類型和對象引用桐玻。基本數(shù)據(jù)類型我們已經(jīng)很清楚了荆萤,那么镊靴,這個對象引用又是什么鬼铣卡?
是這樣的,對象實(shí)例存儲在Java堆中偏竟,通過這個對象引用我們就可以找到對象在堆中的位置煮落。但是,對于如何定位到這個對象踊谋,不同的Java虛擬機(jī)又有不同的方法蝉仇。
通常情況下,有下面兩種方法:
- 使用句柄訪問殖蚕,通常會在Java堆中劃分一塊句柄池轿衔。
- 使用直接指針,這樣Java虛擬機(jī)棧中存儲的就是該對象在堆中的地址睦疫。
這兩種訪問對象的方法各有優(yōu)勢害驹。使用直接指針進(jìn)行訪問,就可以直接定位到對象蛤育,減小了一次指針定位的時間開銷(使用句柄的話會通過句柄池的指針二次定位對象)宛官,最大的好處就是速度更快。但是使用句柄的話瓦糕,就是當(dāng)對象發(fā)生移動的時候底洗,可以不用改變棧中存儲的reference,只需要改變句柄池中實(shí)例數(shù)據(jù)的指針咕娄。
垃圾收集算法
論對象已死亥揖?
前面一部分我們都在講對象,一個對象能夠被創(chuàng)建谭胚,那么這個對象在什么時候被銷毀了徐块?通常,判斷一個對象是否被銷毀有兩種方法:
- 引用計數(shù)算法: 為對象添加一個引用計數(shù)器灾而,每當(dāng)對象在一個地方被引用胡控,則該計數(shù)器加1;每當(dāng)對象引用失效時旁趟,計數(shù)器減1昼激。但計數(shù)器為0的時候,就表白該對象沒有被引用锡搜。
- 可達(dá)性分析算法: 通過一系列被稱之為“GC Roots”的根節(jié)點(diǎn)開始橙困,沿著引用鏈進(jìn)行搜索,凡是在引用鏈上的對象都不會被回收耕餐。
就像上圖的那樣凡傅,綠色部分的對象都在GC Roots的引用鏈上,就不會被垃圾回收器回收肠缔,灰色部分的對象沒有在引用鏈上夏跷,自然就被判定為可回收對象哼转。
那么,問題來了槽华,這個GC Roots又是什么壹蔓?下面列舉可以作為GC Roots的對象:
- Java虛擬機(jī)棧中被引用的對象,各個線程調(diào)用的參數(shù)猫态、局部變量佣蓉、臨時變量等。
- 方法區(qū)中類靜態(tài)屬性引用的對象亲雪,比如引用類型的靜態(tài)變量勇凭。
- 方法區(qū)中常量引用的對象。
- 本地方法棧中所引用的對象义辕。
- Java虛擬機(jī)內(nèi)部的引用套像,基本數(shù)據(jù)類型對應(yīng)的Class對象,一些常駐的異常對象终息。
- 被同步鎖(synchronized)持有的對象。
現(xiàn)在贞让,我們已經(jīng)知道哪些對像是可以回收的周崭。那么又要采取什么方式對對象進(jìn)行回收呢?垃圾回收算法主要有三種喳张,依次是標(biāo)記-清除算法续镇、標(biāo)記-復(fù)制算法、標(biāo)記-整理算法销部。這三種垃圾收集算法其實(shí)也比較容易理解摸航,下面我先介紹概念,然后在依次總結(jié)一下舅桩。
標(biāo)記--清除算法
見名知義酱虎,標(biāo)記--清除算法就是對無效的對象進(jìn)行標(biāo)記,然后清除擂涛。如下圖:
對于標(biāo)記--清除算法读串,你一定會清楚看到,在進(jìn)行垃圾回收之后撒妈,堆空間有大量的碎片恢暖,出現(xiàn)了不規(guī)整的情況。在給大對象分配內(nèi)存的時候狰右,由于無法找到足夠的連續(xù)的內(nèi)存空間杰捂,就不得不再一次觸發(fā)垃圾收集。另外棋蚌,如果Java堆中存在大量的垃圾對象嫁佳,那么垃圾回收的就必然進(jìn)行大量的標(biāo)記和清除動作挨队,這個勢必造成回收效率的降低。
標(biāo)記--復(fù)制算法
標(biāo)記--復(fù)制算法就是把Java堆分成兩塊脱拼,每次垃圾回收時只使用其中一塊瞒瘸,然后把存活的對象全部移動到另一塊區(qū)域。如下圖:
標(biāo)記--復(fù)制算法有一個很明顯的缺點(diǎn)熄浓,那就是每次只使用堆空間的一半情臭,造成了Java堆空間使用率的的下降。
現(xiàn)在大部分Java虛擬機(jī)的垃圾回收器使用的就是標(biāo)記--復(fù)制算法赌蔑,但是俯在,對于Java堆空間的劃分,并不是簡單地一分為二娃惯。
還記得這張圖么跷乐?
前面講Java內(nèi)存結(jié)構(gòu)的時候,提到過Java堆的具體劃分趾浅,那現(xiàn)在就來好好的說一說愕提。
首先得從兩個分代收集理論說起:
- 弱分代假說:大多數(shù)對象的生命存活時間很短。
- 強(qiáng)分代假說:經(jīng)過越多次垃圾收集的對象皿哨,存活的時間就越久浅侨。
正是這兩個分代假說,使得設(shè)計者對Java堆的劃分更加合理证膨。下面如输,來說一下GC的分類:
- Minor GC/Young GC:針對新生代的垃圾收集。
- Major GC/Old GC:針對老年代的垃圾收集央勒。
- Full GC:針對整個Java堆以及方法區(qū)的垃圾收集不见。
好了,知道了GC的分類崔步,是時候知道GC的流程了稳吮。
通常情況下,初次被創(chuàng)建的對象存放在新生代的Eden區(qū)井濒,當(dāng)?shù)谝淮斡|發(fā)Minor GC盖高,Eden區(qū)存活的對象被轉(zhuǎn)移到Survivor區(qū)的某一塊區(qū)域。以后再次觸發(fā)Minor GC的時候眼虱,Eden區(qū)的對象連同一塊Survivor區(qū)的對象一起喻奥,被轉(zhuǎn)移到了另一塊Survivor區(qū)∧笮可以看到撞蚕,這兩塊Survivor區(qū)我們每一次只使用其中的一塊,這樣也僅僅是浪費(fèi)了一塊Survivor區(qū)过牙。
每經(jīng)歷過一次垃圾回收的對象甥厦,它的分代年齡就加1纺铭,當(dāng)分代年齡達(dá)到15以后,就直接被存放到老年代中刀疙。
還有一種情況舶赔,給大對象分配內(nèi)存的時候,Eden區(qū)已經(jīng)沒有足夠的內(nèi)存空間了谦秧,這時候該怎么辦竟纳?對于這種情況,大對象就會直接進(jìn)入老年代疚鲤。
標(biāo)記--整理算法
標(biāo)記--整理算法算是一種折中的垃圾收集算法锥累,在對象標(biāo)記的過程,和前面兩個執(zhí)行的是一樣步驟集歇。但是桶略,進(jìn)行標(biāo)記之后,存活的對象會移動到堆的一端诲宇,然后直接清理存活對象以外的區(qū)域就可以了际歼。這樣,既避免了內(nèi)存碎片姑蓝,也不存在堆空間浪費(fèi)的說法了蹬挺。但是,每次進(jìn)行垃圾回收的時候它掂,都要暫停所有的用戶線程,特別是對老年代的對象回收溯泣,則需要更長的回收時間虐秋,這對用戶體驗是非常不好的。如下圖:
HotSpot的算法細(xì)節(jié)
根節(jié)點(diǎn)枚舉
根節(jié)點(diǎn)枚舉垃沦,其實(shí)就是找出可以作為GC Roots的對象客给,在這個過程中,所有的用戶線程都必須停下肢簿。到目前為止靶剑,幾乎還沒有虛擬機(jī)可以做到GC Roots遍歷與用戶線程并發(fā)執(zhí)行。當(dāng)然池充,可達(dá)性分析算法中最耗時的尋找引用鏈的過程已經(jīng)可以做到和用戶線程并發(fā)執(zhí)行了桩引。那么,為什么需要在根節(jié)點(diǎn)枚舉的時候停止用戶線程收夸?
其實(shí)也不難考慮坑匠,如果進(jìn)行GC Roots遍歷的時候,用戶線程沒有暫停卧惜,根節(jié)點(diǎn)集合的對象引用關(guān)系還在不斷發(fā)生變化厘灼,這樣遍歷到的結(jié)果是不準(zhǔn)確的夹纫。那么,Java虛擬機(jī)在查找GC Roots的時候设凹,是真的需要進(jìn)行全局遍歷舰讹?
其實(shí)不是這樣的,HotSpot虛擬機(jī)通過一個叫做OopMap的數(shù)據(jù)結(jié)構(gòu)闪朱,可以知道哪些地方存儲了對象引用月匣。這樣,大大減小了GC Roots的遍歷時間监透。
安全點(diǎn)
安全點(diǎn)桶错,是線程能夠中斷的點(diǎn)。我們在GC Roots遍歷的時候胀蛮,是一定要讓用戶線程停下來的院刁。問題來了,線程是可以在任意位置停下來嗎粪狼?為了使得線程到達(dá)最近的安全點(diǎn)停下來退腥,有兩種思路:
- 搶先式中斷: 暫停所有的用戶線程,如果哪條線程沒有在安全點(diǎn)再榄,就恢復(fù)這條線程執(zhí)行狡刘,直到它跑到安全點(diǎn)上在中斷。不過沒有Java虛擬機(jī)采用這種思路困鸥。
- 主動式中斷: 不對線程進(jìn)行操作嗅蔬,僅僅設(shè)置一個簡單的標(biāo)志位,線程執(zhí)行的時候不斷區(qū)輪詢這個標(biāo)志位疾就,當(dāng)這個標(biāo)志位為真的時候澜术,線程就在離自己最近的安全點(diǎn)掛起。
安全區(qū)域
安全區(qū)域是安全點(diǎn)的拉伸和擴(kuò)展猬腰,安全點(diǎn)解決了如何讓線程停下鸟废,卻沒有解決如何讓虛擬機(jī)進(jìn)入垃圾回收狀態(tài)。
安全區(qū)域是指能能夠確保在某一代碼片段中姑荷,引用關(guān)系不會發(fā)生變化的區(qū)域盒延。因此,一旦線程進(jìn)入了安全區(qū)域鼠冕,就可以不去理會這些處于安全區(qū)域的線程添寺。當(dāng)線程離開安全區(qū)域的時候,虛擬機(jī)就會檢查是否完成了根節(jié)點(diǎn)枚舉懈费。
記憶集與卡表
不知道大家是否考慮過這樣的一個問題畦贸?既然Java堆有新生代老年代的劃分,那么對象引用是否會存在跨代?如果存在跨代薄坏,又該如何解決老年代的GC Roots遍歷問題趋厉?
首先,跨代引用是存在的胶坠。因此君账,垃圾收集器在新生代建立了一個叫做記憶集的數(shù)據(jù)結(jié)構(gòu),用來避免把整個老年代假如GC Roots的掃描范圍沈善。
記憶集是抽象的數(shù)據(jù)結(jié)構(gòu)乡数,而卡表是記憶集的具體實(shí)現(xiàn),這種關(guān)系就類似與方法區(qū)與元空間闻牡。
寫屏障
寫屏障的作用很簡單净赴,就是對卡表進(jìn)行維護(hù)和更新。
并發(fā)的可達(dá)性分析
前面我們說到過為什么要暫停所有的用戶線程(這個動作也被稱之為Stop The World)罩润?這其實(shí)是為了不讓用戶線程改變GC Roots對象的引用玖翅。試想,如果用戶線程能夠隨便把死亡的對象重新標(biāo)記為存活割以,或者把存活的對象標(biāo)記為死亡金度,這豈不是會使的程序發(fā)生意想不到的錯誤。
經(jīng)典的垃圾收集器
知道了不少的垃圾收集理論严沥,但是具體到某一類的垃圾收集器猜极,其實(shí)現(xiàn)方式又不全然相同。下面就介紹一些常見的垃圾收集器消玄。
Serial 收集器
Serial 收集器是最基礎(chǔ)跟伏、歷史最悠久的收集器,它在進(jìn)行垃圾收集的時候會暫停所有的工作線程翩瓜,直到完成垃圾收集過程受扳。下面是Serial垃圾收集器的運(yùn)行示意圖:
ParNew 收集器
ParNew 垃圾收集器實(shí)則是Serial 垃圾收集器的多線程版本,這個多線程在于ParNew垃圾收集器可以使用多條線程進(jìn)行垃圾回收奥溺。
Parallel Scavenge 收集器
也是一款新生代垃圾收集器,同樣的基于標(biāo)記--復(fù)制算法實(shí)現(xiàn)的骨宠。它最大的特點(diǎn)是可以控制吞吐量浮定。
那什么是吞吐量呢?
Serial Old 收集器
Serial Old 收集器是Serial 收集器的老年代版本层亿。其垃圾收集器的運(yùn)行原理和Serial 收集器是一樣的桦卒。
Parallel Old 收集器
Parallel Old 收集器同樣是Parallel Scavenge 收集器的老年代版本,支持多線程并發(fā)收集匿又。下面就是它的運(yùn)行示意圖:
CMS 收集器
前面說到過Parallel Scavenge 收集器方灾,它是一個可以控制吞吐量的垃圾收集器。現(xiàn)在要說的CMS 收集器,它是一個追求最短停頓時間的垃圾收集器裕偿,基于標(biāo)記--清除算法實(shí)現(xiàn)的洞慎。CMS 垃圾收集器的運(yùn)作過程相對前面幾個垃圾收集器來說比較復(fù)雜,整個過程可以分為四個部分:
- 初始標(biāo)記: 需要Stop The World嘿棘,這里僅僅標(biāo)記GC Roots能夠直接關(guān)聯(lián)的對象劲腿,所以速度很快。
- 并發(fā)標(biāo)記: 從關(guān)聯(lián)對象遍歷整個GC Roots的引用鏈鸟妙,這個過程耗時最長焦人,但是卻可以和用戶線程并發(fā)運(yùn)行。
- 重新標(biāo)記: 修正并發(fā)時間重父,因為用戶線程可能會導(dǎo)致標(biāo)記產(chǎn)生變動花椭,同樣需要Stop The World。
- 并發(fā)清除: 清除已經(jīng)死亡的對象房午。
Garbage First 收集器
Garbage First(簡稱G 1)收集器是垃圾收集器發(fā)展史上里程碑式的成果矿辽,主要面向服務(wù)端應(yīng)用程序。另外G 1收集器雖然還保留新生代和老年代的概念歪沃,但是新生代和老年代不在固定嗦锐,它們都是一系列區(qū)域的動態(tài)集合。
好了沪曙,關(guān)于垃圾收集器就介紹到這里奕污,至于G 1收集器還是有很多地方需要關(guān)注的,朋友們可以查閱相關(guān)資料液走。下一篇碳默,我們講類加載機(jī)制,你們說好么缘眶?
現(xiàn)在是凌晨兩點(diǎn)半嘱根,慶幸我沒看到凌晨四點(diǎn)的太陽。上帝會帶走他最喜歡的兒子么巷懈?還是那句話该抒,原創(chuàng)不易,點(diǎn)贊再看顶燕,最后加個關(guān)注凑保,定期推送原創(chuàng)高質(zhì)量文章。
最后的最后涌攻,上點(diǎn)干貨欧引。(但凡有個這樣的女朋友,我會熬夜么恳谎?)