垃圾收集器與內(nèi)存分配策略

? ? ? ? 在Java中有一套完整的內(nèi)存動(dòng)態(tài)分配和垃圾收集(Garbage Collection,GC)機(jī)制剩檀,可以實(shí)現(xiàn)自動(dòng)化的內(nèi)存動(dòng)態(tài)分配和垃圾回收逆屡,了解這一機(jī)制,我們可以在排查內(nèi)存溢出赘被、內(nèi)存泄漏問(wèn)題時(shí)悴侵,實(shí)現(xiàn)系統(tǒng)更高并發(fā)量時(shí)對(duì)這一自動(dòng)化技術(shù)實(shí)施監(jiān)控和調(diào)節(jié)瞧剖。

? ? ? ? 在Java內(nèi)存運(yùn)行時(shí),程序計(jì)數(shù)器畜挨、虛擬機(jī)棧筒繁、本地方法棧的內(nèi)存分配和回收都是已知確定的,因此不用過(guò)多考慮回收問(wèn)題巴元。而Java堆和方法區(qū)內(nèi)存的分配和回收是動(dòng)態(tài)的毡咏,垃圾收集器關(guān)注的是這部分的內(nèi)存。

判斷對(duì)象是否死亡

判斷對(duì)象是否死亡有兩種算法:

(1)引用計(jì)數(shù)算法:給對(duì)象添加一個(gè)計(jì)數(shù)器逮刨,當(dāng)有一個(gè)地方引用它時(shí)計(jì)數(shù)器值加1呕缭,當(dāng)引用失效時(shí),計(jì)數(shù)器值減1修己。計(jì)數(shù)器為0的對(duì)象是不再被引用的恢总,當(dāng)該算法無(wú)法解決的是對(duì)象之間相互循環(huán)引用的問(wèn)題,關(guān)于這個(gè)問(wèn)題睬愤,可參考:http://blog.csdn.net/u010253968/article/details/51160703

(2)可達(dá)性分析算法:當(dāng)一個(gè)對(duì)象沒(méi)有被稱(chēng)為“GC Roots”的對(duì)象直接間接引用時(shí)片仿,及GC Roots到該對(duì)象不可達(dá)時(shí),此對(duì)象是不可用的尤辱。例如:GC Roots對(duì)象引用了object1砂豌,object1引用了object2厢岂,那么object1和object2都是可用的,因?yàn)樗鼈兌急籊C Roots對(duì)象直接或間接引用了阳距。而如果object3引用了object4塔粒,object4引用了object5,盡管它們都有被其他對(duì)象引用筐摘,但它們都沒(méi)有被GC Roots對(duì)象引用卒茬,所以它們都是不可用的。而GC Roots對(duì)象包括以下幾種:

a.虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象

b.方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象

c.方法區(qū)中常量引用的對(duì)象

d.本地方法棧中JNI(Native方法)引用的對(duì)象

引用

引用分為四種:

(1)強(qiáng)引用:程序代碼之中普遍存在的咖熟,只要強(qiáng)引用還在圃酵,垃圾收集器永遠(yuǎn)不會(huì)回收被引用的對(duì)象

(2)軟引用:有用但并非必要的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前馍管,將會(huì)把這些對(duì)象列入回收范圍進(jìn)行第二次回收

(3)弱引用:被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前

(4)虛引用:虛引用不會(huì)對(duì)對(duì)象的生存周期構(gòu)成影響辜昵,也無(wú)法通過(guò)虛引用來(lái)獲取一個(gè)對(duì)象,虛引用的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知

對(duì)象的自我拯救

在可達(dá)性分析算法中的不可達(dá)對(duì)象咽斧,還會(huì)經(jīng)過(guò)一次篩選,躬存,篩選出有必要執(zhí)行finalize()方法的對(duì)象张惹,然后虛擬機(jī)會(huì)觸發(fā)這個(gè)方法,但并不一定會(huì)等待到它運(yùn)行結(jié)束岭洲。如果對(duì)象要在finalize()方法中拯救自己宛逗,可以在這個(gè)方法中重新與GC Roots對(duì)象建立直接或間接的關(guān)聯(lián)就可以存活。但在實(shí)際開(kāi)發(fā)中因盡量避免該方法

回收方法區(qū)

在方法區(qū)中垃圾收集效率比較低盾剩,一次能回收的空間比較少雷激,主要回收兩部分內(nèi)容:廢棄常量和無(wú)用的類(lèi),類(lèi)需要滿(mǎn)足以下條件才能算是無(wú)用的類(lèi):

(1)該類(lèi)的所有實(shí)例都已經(jīng)被回收告私,也就是Java堆中不存在該類(lèi)的任何實(shí)例

(2)加載該類(lèi)的ClassLoader已經(jīng)被回收

(3)該類(lèi)對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用屎暇,無(wú)法在任何地方通過(guò)反射訪(fǎng)問(wèn)該類(lèi)的方法

垃圾收集算法

標(biāo)記-清除算法:首先標(biāo)記出需要回收的對(duì)象,然后統(tǒng)一回收驻粟,是最基本的收集算法根悼,其它算法是對(duì)其不足進(jìn)行改進(jìn)而得到的。主要有兩個(gè)不足:一是效率不高蜀撑,二是會(huì)產(chǎn)生大量不連續(xù)的空間碎片

復(fù)制算法:將內(nèi)存分為兩塊挤巡,每次只使用其中一塊,當(dāng)這一塊內(nèi)存用完了酷麦,就把存活的對(duì)象復(fù)制到另一塊矿卑,然后清空使用過(guò)的內(nèi)存。這種算法的代價(jià)是將內(nèi)存縮小為原來(lái)的一半

標(biāo)記-整理算法:標(biāo)記過(guò)程與“標(biāo)記-清理”算法一樣沃饶,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理母廷,而是所有存活對(duì)象都向一端移動(dòng)轻黑,然后直接清理邊界以外的內(nèi)存

分代收集算法:把Java堆分為新生代和老年代,對(duì)應(yīng)每次垃圾收集都有大量對(duì)象死去的新生代采用復(fù)制算法徘意,這樣復(fù)制的成本刑υ谩;而對(duì)于對(duì)象存活率高的老年代椎咧,使用“標(biāo)記-清除”算法或者“標(biāo)記-整理”進(jìn)行回收

HotSpot的算法實(shí)現(xiàn)

HotSpot虛擬機(jī)在實(shí)現(xiàn)對(duì)象存活判定算法和垃圾回收算法時(shí)玖详,必須保證虛擬機(jī)高效運(yùn)行。

枚舉根節(jié)點(diǎn):

枚舉根節(jié)點(diǎn)對(duì)時(shí)間的敏感性:一方面勤讽,在垃圾回收過(guò)程中蟋座,用可達(dá)性分析算法判斷對(duì)象是否存活時(shí),為保證判斷結(jié)果的準(zhǔn)確性脚牍,必須停頓所有Java執(zhí)行線(xiàn)程使對(duì)象引用關(guān)系不發(fā)生變化向臀,所以枚舉根節(jié)點(diǎn)必須停頓。另一方面诸狭,可作為GC Roots的節(jié)點(diǎn)主要在全局性的引用(例如常量或類(lèi)靜態(tài)屬性)與執(zhí)行上下文(例如棧幀中的本地變量表)券膀,在很多應(yīng)用里,僅僅在方法區(qū)中就有幾百兆驯遇,如果要逐個(gè)檢查它們直接或間接引用的對(duì)象芹彬,會(huì)消耗很多時(shí)間,而消耗的時(shí)間越多叉庐,停頓的時(shí)間越長(zhǎng)舒帮。

解決這些不足的方法:執(zhí)行系統(tǒng)停頓時(shí),不需要逐個(gè)檢查陡叠,而是在類(lèi)加載完成時(shí)玩郊,就把對(duì)象內(nèi)什么偏移量上是什么類(lèi)型的數(shù)據(jù)計(jì)算出來(lái)并用特定數(shù)據(jù)結(jié)構(gòu)表示出來(lái),在JIT編譯過(guò)程中枉阵,也會(huì)在特定的位置使用特定的數(shù)據(jù)結(jié)構(gòu)記錄下棧和寄存器中那些位置是引用译红,如Hotpot使用一組稱(chēng)為OopMap的數(shù)據(jù)結(jié)構(gòu)。這樣岭妖,GC 在掃描是可以直接得知這些信息临庇。

安全點(diǎn):

如果每一條指令都生成對(duì)應(yīng)的OopMap,則需要大量的額外空間昵慌,GC的空間成本會(huì)變得非常高假夺,所以只是在“特定的位置”生成了對(duì)應(yīng)的OopMap,這些位置就成為安全點(diǎn)(Safepoint)斋攀,程序在執(zhí)行到安全點(diǎn)才能停頓下來(lái)GC已卷。一般指令序列復(fù)用如方法調(diào)用、循環(huán)跳轉(zhuǎn)淳蔼、異常跳轉(zhuǎn)等情況下侧蘸,才會(huì)產(chǎn)生安全點(diǎn)裁眯,因?yàn)檫@些情況需要長(zhǎng)時(shí)間執(zhí)行。

對(duì)應(yīng)于安全點(diǎn)讳癌,需要考慮如何在GC發(fā)生時(shí)讓所有的線(xiàn)程執(zhí)行到最近的安全點(diǎn)再停頓下來(lái)穿稳,有兩種方法:

(1)搶先式中斷:GC發(fā)生時(shí),先把所以線(xiàn)程中斷晌坤,如果有線(xiàn)程中斷的地方不在安全點(diǎn)逢艘,就恢復(fù)線(xiàn)程,讓它執(zhí)行到安全點(diǎn)上骤菠,現(xiàn)在幾乎已經(jīng)不使用這種方式它改。

(2)主動(dòng)式中斷:當(dāng)GC需要中斷線(xiàn)程時(shí),不對(duì)線(xiàn)程操作商乎,只設(shè)置一個(gè)標(biāo)志央拖,各個(gè)線(xiàn)程主動(dòng)去輪詢(xún)這個(gè)標(biāo)志,如果這個(gè)中斷標(biāo)志為真就自己中斷掛起鹉戚,一般輪詢(xún)標(biāo)志的地方與安全點(diǎn)重合鲜戒。

安全區(qū)域:

線(xiàn)程處于Sleep狀態(tài)或者Blocked狀態(tài)等“不執(zhí)行”的狀態(tài)時(shí),無(wú)法響應(yīng)JVM的中斷請(qǐng)求抹凳,執(zhí)行到安全點(diǎn)然后中斷掛起袍啡,這時(shí)候就需要安全區(qū)域(Safe Region)來(lái)解決。安全區(qū)域指在一段代碼片段中却桶,引用關(guān)系不會(huì)發(fā)生變化,在這個(gè)區(qū)域中能中的任意地方開(kāi)始GC都是安全的蔗牡。

當(dāng)線(xiàn)程執(zhí)行到Safe Region中的代碼時(shí)颖系,首先標(biāo)識(shí)自己進(jìn)入了安全區(qū)域,當(dāng)JVM要發(fā)起GC時(shí)辩越,就不用管標(biāo)志自己為安全區(qū)狀態(tài)的線(xiàn)程了嘁扼。當(dāng)線(xiàn)程要離開(kāi)安全區(qū)域時(shí),要檢查系統(tǒng)是否完成了根節(jié)點(diǎn)枚舉或者整個(gè)GC過(guò)程黔攒,如果完成了趁啸,就可以離開(kāi)安全區(qū)域,否則就要等到收到可以離開(kāi)Safe Region的信號(hào)為止督惰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末不傅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赏胚,更是在濱河造成了極大的恐慌访娶,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觉阅,死亡現(xiàn)場(chǎng)離奇詭異崖疤,居然都是意外死亡秘车,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)劫哼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叮趴,“玉大人,你說(shuō)我怎么就攤上這事权烧∶幸啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵豪嚎,是天一觀(guān)的道長(zhǎng)搔驼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)侈询,這世上最難降的妖魔是什么舌涨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮扔字,結(jié)果婚禮上囊嘉,老公的妹妹穿的比我還像新娘。我一直安慰自己革为,他們只是感情好扭粱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著震檩,像睡著了一般琢蛤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抛虏,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天博其,我揣著相機(jī)與錄音,去河邊找鬼迂猴。 笑死慕淡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沸毁。 我是一名探鬼主播峰髓,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼息尺!你這毒婦竟也來(lái)了携兵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤搂誉,失蹤者是張志新(化名)和其女友劉穎眉孩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浪汪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年巴柿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片死遭。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡广恢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呀潭,到底是詐尸還是另有隱情钉迷,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布钠署,位于F島的核電站糠聪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谐鼎。R本人自食惡果不足惜舰蟆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狸棍。 院中可真熱鬧身害,春花似錦、人聲如沸草戈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)唐片。三九已至丙猬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間费韭,已是汗流浹背淮悼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揽思,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓见擦,卻偏偏與公主長(zhǎng)得像钉汗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鲤屡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容