垃圾回收機制與內(nèi)存分配策略

Java與C++ 之間有一堵由內(nèi)存動態(tài)分配和垃圾收集技術(shù)所圍成的高墻,墻外的人想進去务漩,墻外的人想出來巡蘸。


垃圾收集大部分人都吧這項技術(shù)當做Java語言的伴生產(chǎn)物。


前面介紹了Java內(nèi)存運行時各區(qū)域的各個部分俭驮,其中程序計數(shù)器回溺、虛擬機棧、本地方法棧3各區(qū)域隨線程而生,隨線程而滅:棧中的棧幀隨著方法的進入和退出而有條不紊的執(zhí)行出棧和入棧操作馅而。每個棧幀中分配多少內(nèi)存基本上都是在類結(jié)構(gòu)確定下來時就已知的(盡管在運行時期會由JIT編譯器進行一些優(yōu)化,但在本章基于概念模型的談?wù)撝衅┦ィ篌w上可以認為是編譯器可知的)因此這幾個區(qū)域的內(nèi)存分配和回收都是具備確定性在這幾個區(qū)域內(nèi)就不需要過多久考慮回收的問題瓮恭。因為方法結(jié)束或者線程結(jié)束時,內(nèi)存就自然跟隨者回收了厘熟。而Java 方法區(qū)則不一樣屯蹦,一個接口中的多個實現(xiàn)類需要的內(nèi)存可能不一樣,一個方法中的多個分支需要的內(nèi)存也可能不一樣绳姨,我們只有在程序處于運行期間時才能知道會創(chuàng)建哪些對象登澜,這部分內(nèi)存的分配和回收都是動態(tài)的,垃圾回收機器所關(guān)注是這部分內(nèi)存飘庄。后續(xù)討論的也是這部分內(nèi)存

在堆里面存放著Java世界中幾乎所有的對象實例脑蠕,垃圾收集器在對堆進行回收前,第一件事情就是要確定這些對象之中哪些還“存活”著跪削,哪些已經(jīng)“死去”(即不可能再被任何途徑使用的對象)


引用計數(shù)法給對象中添加一個引用計數(shù)器谴仙,每當有一個地方引用它時,計數(shù)器就加1碾盐;當引用失效時晃跺,計數(shù)器就減一;任何時刻計數(shù)器為0的對象就是不可能被再使用的.主流的Java虛擬機里面沒有選用引用計數(shù)法來管理內(nèi)存毫玖,其中最主要的 原因就是很難解決對象之間相互循環(huán)引用的問題掀虎。


可達性分析算法在主流的商用程序語言的主流實現(xiàn)中,都是稱通過可達性分析來判斷對象是否存活的付枫。這個算法的基本思想就是通過一系列的稱為“GC roots”的對象作為起始點烹玉,從這些節(jié)點開始向下搜索,搜索走過的路徑稱為引用鏈励背,當一個對象到GC Roots沒有任何引用鏈相連春霍,則證明此對象不可用。

在Java語言中叶眉,可作為GC Roots的對象包括下面幾種:
1.虛擬機棧
2.方法區(qū)中類靜態(tài)屬性引用的對象址儒。
3.方法區(qū)中常量引用的對象
4.本地方法棧中JNI(Native方法)引用的對象。
無論是通過引用計數(shù)算法判斷對象的引用數(shù)量衅疙,還是通過可達性分析算法判斷對象的引用鏈是否可達莲趣,判定對象是否存活都與‘引用’有關(guān)。Java中的引用定義很傳統(tǒng):如果reference類型的數(shù)據(jù)中存儲的數(shù)值代表的是另外一塊內(nèi)存的起始地址饱溢,就稱這塊內(nèi)存代表著一個引用喧伞。JDK1.2之后,Java將引用分為強引用軟引用潘鲫、弱引用翁逞、虛引用、溉仑。4種引用強度依次減弱挖函。


強引用:指程序代碼中普遍存在的,類型 Object obj = new Object(); 這類的引用浊竟。只要引用還存在怨喘,垃圾回收器永遠不會回收掉被引用的對象。
軟引用:是用來描述非必須對象的振定,對于軟引用關(guān)聯(lián)著的對象必怜,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會把這些對象列進回收范圍之中進行第二次回收后频。如果這次回收還沒有足夠的內(nèi)存才會拋出內(nèi)存溢出異常梳庆。
弱引用是用來描述非必須對象的,但是他的強度比軟引用更弱一些卑惜,被弱引用關(guān)聯(lián)的對象只能夠生存到下一次垃圾回收之前靠益,當垃圾收集器工作時,無論當前內(nèi)存是否足夠残揉,都會回收掉只被弱引用關(guān)聯(lián)的對象胧后。
虛引用它是最弱的一種引用關(guān)系。一個對象是否有虛引用的存在抱环,完全不會對生存時間夠成影響壳快。,也無法通過虛引用取得一個對象實例镇草。為一個對象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在對象被垃圾器回收時收到一個系統(tǒng)通知眶痰。


生存還是死亡:即時在可達性分析算法中不可達的對象,也并非是“非死不可”的梯啤,這時候他們暫時處于緩刑階段竖伯,要真正宣告一個對象死亡,至少要經(jīng)歷兩次標記過程:如果對象在進行可達性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈因宇,那么它將會第一次標記且進行一次篩選七婴,篩選條件是次對象是否有必要執(zhí)行finalize()方法。當一個對象覆蓋finalize()方法察滑,或者finalize()方法已經(jīng)被虛擬機調(diào)用過打厘,虛擬機將這兩種情況視為“沒有必要執(zhí)行『爻剑”
如果這個對象被判定為有不要執(zhí)行finalize()方法户盯,那么這個對象將會放置在一個叫做F-Queue的隊列之中嵌施,并在稍后由虛擬機自動建立的,低優(yōu)先級的Finalizer線程去執(zhí)行它莽鸭,這些所謂的執(zhí)行是指虛擬機觸發(fā)這個方法吗伤,但不會承諾等待它運行結(jié)束,這樣做的原因是硫眨,如果一個對象在finalize()方法中執(zhí)行緩慢牲芋,或者發(fā)生了死循環(huán),將很有可能導(dǎo)致F-Queue隊列中其他對象用于處于等待捺球,甚至導(dǎo)致整個內(nèi)存回收系統(tǒng)奔潰。finalize()方法是對象逃脫死亡命運的最后一次機會夕冲,稍后GC將會對F-Queue中的對象進行第二次小規(guī)模標記氮兵,如果對象要在finalize()中成功拯救自己-只要重新與引用鏈上的任何一個對象建立關(guān)聯(lián)即可。譬如把自己賦值給某個類變量或者對象的成員變量歹鱼,那么在第二次標記時它將會被移除‘即將回收’的集合泣栈;如果對象這個時候還沒有逃脫,那基本上他就真的被回收了弥姻。


回收方法區(qū)Java虛擬機規(guī)范確實說過可以不要求虛擬機在方法區(qū)實現(xiàn)垃圾收集南片,而且在方法區(qū)中進行垃圾收集的‘性價比’一般較低;在堆中庭敦,尤其在新生代中疼进,常規(guī)應(yīng)用進行一次垃圾收集一般可以回收50%~95%的空間,而永久代的垃圾回收效率遠遠低于此秧廉。
永久代的垃圾回收集主要回收兩部分內(nèi)容=廢棄常量和無用的類伞广。回收廢棄常量與回收Java堆中的對象非常類似疼电。

以常量池中字面量的回收為例嚼锄,假如一個字符串“adc”已經(jīng)進常量池中,但是系統(tǒng)當前沒有任何一個String對象是叫做“abc”蔽豺,話句話說区丑,就是沒有任何String對象引用常量池中的“abc”常量,也沒有其他引用了這個字面量修陡,如果這是發(fā)生內(nèi)存回收沧侥,而且必要的話,“abc”常量會被系統(tǒng)清出常量池魄鸦。常量池中其他類(接口)正什、方法、字段的符號引用與此類似号杏。


判定一個類是否“無用的類”的條件則相對苛刻很多婴氮,同時滿足3個條件才能算是“無用的類”:
1.該類所有的實例都已經(jīng)被回收斯棒,也就是Java堆中不存在該類的任何實例。
2.加載該類的ClassLoader已經(jīng)回收主经。
3.該類對應(yīng)的java.lang.Class 對象沒有在任何地方被調(diào)用荣暮,無法在任何地方通過反射訪問該類的方法。

虛擬機可以對滿足上述3個條件的無用類進行回收罩驻,這里說的僅僅是“可以”穗酥,并不是和對象一樣,不使用必然回收惠遏。是否對類進行回收砾跃,HotSpot虛擬機提供了 -Xnocalssgc 參數(shù)進行控制。在大量使用反射节吮、動態(tài)代理抽高、CGLib等ByteCode框架、動態(tài)生成JSP以及OSGI這類頻繁自定義ClassLoader
的場景都需要虛擬機具備卸載的功能透绩,以保證永久代不會溢出翘骂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帚豪,隨后出現(xiàn)的幾起案子碳竟,更是在濱河造成了極大的恐慌,老刑警劉巖狸臣,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莹桅,死亡現(xiàn)場離奇詭異,居然都是意外死亡烛亦,警方通過查閱死者的電腦和手機统翩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來此洲,“玉大人厂汗,你說我怎么就攤上這事∥厥Γ” “怎么了娶桦?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長汁汗。 經(jīng)常有香客問我衷畦,道長,這世上最難降的妖魔是什么知牌? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任祈争,我火速辦了婚禮,結(jié)果婚禮上角寸,老公的妹妹穿的比我還像新娘菩混。我一直安慰自己忿墅,他們只是感情好,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布沮峡。 她就那樣靜靜地躺著疚脐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邢疙。 梳的紋絲不亂的頭發(fā)上棍弄,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機與錄音疟游,去河邊找鬼呼畸。 笑死,一個胖子當著我的面吹牛颁虐,可吹牛的內(nèi)容都是我干的蛮原。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聪廉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了故慈?” 一聲冷哼從身側(cè)響起板熊,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎察绷,沒想到半個月后干签,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡拆撼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年容劳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闸度。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡竭贩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莺禁,到底是詐尸還是另有隱情留量,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布哟冬,位于F島的核電站楼熄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浩峡。R本人自食惡果不足惜可岂,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翰灾。 院中可真熱鬧缕粹,春花似錦稚茅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至双戳,卻和暖如春虹蒋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背飒货。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工魄衅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人塘辅。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓晃虫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扣墩。 傳聞我的和親對象是個殘疾皇子哲银,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

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

  • 概述 觀察Java內(nèi)存運行時區(qū)域的各個部分,其中程序計數(shù)器呻惕、Java虛擬機棧荆责、本地方法棧3個區(qū)域隨線程而生,隨線程...
    Steven1997閱讀 596評論 0 0
  • Java和C++之間有一堵由內(nèi)存動態(tài)分配和垃圾收集技術(shù)所圍成的“高墻”亚脆,墻外面的人想進來做院,墻里面的人想出來。 對象...
    胡二囧閱讀 1,087評論 0 4
  • 1.什么是垃圾回收濒持? 垃圾回收(Garbage Collection)是Java虛擬機(JVM)垃圾回收器提供...
    簡欲明心閱讀 89,484評論 17 311
  • 我挺喜歡天道這部電視局键耕,里面講的文化屬性很值得人去深思,還有一句禪語柑营,神穊道屈雄,道法自然,如來官套!一句話概括了神佛道棚亩,...
    f982bf4c669e閱讀 202評論 0 0
  • 花開花落,人來人往虏杰。三年前讥蟆,我們匆匆赴約,三年后纺阔,我們紛亂散場瘸彤。我們似乎該哭該鬧,卻不言不語的微笑笛钝,眼眶微紅质况,...
    孤鯨落閱讀 201評論 0 0