JAVA垃圾回收

JAVA垃圾回收

時(shí)間:20180307


問(wèn)題:

  • 如何判定對(duì)象為垃圾對(duì)象
    • 引用計(jì)數(shù)法
    • 可達(dá)性分析法
  • 如何回收
    • 回收策略
      • 標(biāo)記-清除
      • 復(fù)制算法
      • 標(biāo)記-整理算法
      • 分代收集算法
    • 垃圾回收器
      • Serial
      • Parnew
      • Cms
      • G1
  • 何時(shí)回收

引用計(jì)數(shù)法

??很多教科書(shū)給出如下定義:給對(duì)象添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí)屋确,計(jì)數(shù)器值加1曹宴;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1佑附;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。
??但是,至少主流的JAVA虛擬機(jī)里面沒(méi)有選用引用計(jì)數(shù)法來(lái)管理內(nèi)存观游,其中最主要的原因就是它很難解決對(duì)象之間的循環(huán)引用的問(wèn)題永票。

打印詳細(xì)的GC日志信息參數(shù)(VM arguments):
-verbose:gc
-XX:+PrintGCDetails

測(cè)試堆中多個(gè)對(duì)象之間存在循環(huán)引用卵贱,外部沒(méi)有引用,垃圾回收情況:

public class Main {
    public Object instance = null;
    public static void main(String[] args) {
        Main m1 = new Main();
        Main m2 = new Main();
        m1.instance = m2;
        m2.instance = m1;
        m1 = null;
        m2 = null;
        System.gc();
    }
}

結(jié)果:
[GC (System.gc()) [PSYoungGen: 1996K->936K(38400K)] 1996K->944K(125952K), 0.0012261 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 936K->0K(38400K)] [ParOldGen: 8K->565K(87552K)] 944K->565K(125952K), [Metaspace: 2735K->2735K(1056768K)], 0.0054020 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 38400K, used 333K [0x00000000d5900000, 0x00000000d8380000, 0x0000000100000000)
eden space 33280K, 1% used [0x00000000d5900000,0x00000000d59534a8,0x00000000d7980000)
from space 5120K, 0% used [0x00000000d7980000,0x00000000d7980000,0x00000000d7e80000)to space 5120K, 0% used [0x00000000d7e80000,0x00000000d7e80000,0x00000000d8380000)
ParOldGen total 87552K, used 565K [0x0000000080a00000, 0x0000000085f80000, 0x00000000d5900000)
object space 87552K, 0% used [0x0000000080a00000,0x0000000080a8d770,0x0000000085f80000)
Metaspace used 2741K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 304K, capacity 386K, committed 512K, reserved 1048576K

public class Main {
    public Object instance = null;
    public Main() {
        byte [] m = new byte[20 * 1024 * 1024];
    }
    public static void main(String[] args) {
        Main m1 = new Main();
        Main m2 = new Main();
        m1.instance = m2;
        m2.instance = m1;
        m1 = null;
        m2 = null;
        System.gc();
    }
}

結(jié)果:
[GC (System.gc()) [PSYoungGen: 22476K->872K(38400K)] 42956K->21360K(125952K), 0.0010626 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 872K->0K(38400K)] [ParOldGen: 20488K->565K(87552K)] 21360K->565K(125952K), [Metaspace: 2735K->2735K(1056768K)], 0.0052890 secs] [Times: user=0.14 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 38400K, used 333K [0x00000000d5900000, 0x00000000d8380000, 0x0000000100000000)
eden space 33280K, 1% used [0x00000000d5900000,0x00000000d59534a8,0x00000000d7980000)
from space 5120K, 0% used [0x00000000d7980000,0x00000000d7980000,0x00000000d7e80000)
to space 5120K, 0% used [0x00000000d7e80000,0x00000000d7e80000,0x00000000d8380000)
ParOldGen total 87552K, used 565K [0x0000000080a00000, 0x0000000085f80000, 0x00000000d5900000)
object space 87552K, 0% used [0x0000000080a00000,0x0000000080a8d770,0x0000000085f80000)
Metaspace used 2741K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 304K, capacity 386K, committed 512K, reserved 1048576K

圖解:

引用計(jì)數(shù)法垃圾回收驗(yàn)證

可達(dá)性分析算法

這個(gè)算法的基本思路就是通過(guò)一系列的稱(chēng)為“GC Roots”的對(duì)象作為起點(diǎn)侣集,從這個(gè)節(jié)點(diǎn)開(kāi)始向下搜索键俱,搜索走過(guò)的路徑稱(chēng)為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈時(shí)世分,則證明此對(duì)象是不可用的编振。就是從GCRoots到這個(gè)對(duì)象是不可達(dá)的。
可作為G'C'Roots的對(duì)象

  • 虛擬機(jī)棧(局部變量表)
  • 方法區(qū)的類(lèi)靜態(tài)屬性所引用的對(duì)象
  • 方法區(qū)中常量所引用的對(duì)象
  • 本地方法棧中引用的對(duì)象

垃圾收集算法

標(biāo)記-清楚算法

最基礎(chǔ)的收集算法是“標(biāo)記-清除(Mark-Sweep)”算法臭埋,如同它的名字一樣踪央,算法分為“標(biāo)記”和"清除"兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記后統(tǒng)一回收所有被標(biāo)記的對(duì)象瓢阴。標(biāo)記過(guò)程就是(可達(dá)性分析算法)畅蹂。
不足之處
1.效率問(wèn)題:標(biāo)記和清除兩個(gè)過(guò)程的效率都不高。
2.空間問(wèn)題:標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片炫掐,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí)魁莉,無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。

復(fù)制算法

復(fù)制算法:它將可用內(nèi)存按容量劃分為大小相等的涼快募胃,每次只使用其中的一塊旗唁,當(dāng)這一塊的內(nèi)存用完了,就將還存活的對(duì)象復(fù)制到另一塊上面痹束,然后再把已使用過(guò)的內(nèi)存空間一次清理掉检疫。

1.新生代

  • Eden 伊甸園
  • Survivor 存活區(qū)
  • Tenured Gen

    2.老年代
標(biāo)記 -整理算法

標(biāo)記-整理算法有可以叫做標(biāo)記-整理-清除算法。其中標(biāo)記過(guò)程仍然與“標(biāo)記-清除”算法一樣祷嘶,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理屎媳,而是讓所有存活的對(duì)象都向一端移動(dòng)夺溢,然后直接清理掉端邊界以外的內(nèi)存(被標(biāo)記需要清除的對(duì)象)。
復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作烛谊,效率將會(huì)變低风响。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間丹禀,就需要有額外的空間進(jìn)行分配擔(dān)保状勤,已應(yīng)對(duì)被使用的內(nèi)存中對(duì)象都100%存活的極端情況,所以在老年代一般不能直接用這種算法双泪。

分代收集算法

??當(dāng)前商業(yè)虛擬機(jī)的垃圾收集都采用“分代收集Generational Collection算法”持搜,只是根據(jù)對(duì)象存活的周期的不同將內(nèi)存劃分為幾塊。一般把JAVA堆分為新生代和老年代焙矛。這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適合的收集算法葫盼。在新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去村斟,只有少量存活贫导,那就使用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集蟆盹。而老年代中因?yàn)閷?duì)象存活率高脱盲、沒(méi)有額外的空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記-清理”或者“標(biāo)記-整理”算法來(lái)進(jìn)行回收日缨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市掖看,隨后出現(xiàn)的幾起案子匣距,更是在濱河造成了極大的恐慌,老刑警劉巖哎壳,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毅待,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡归榕,警方通過(guò)查閱死者的電腦和手機(jī)尸红,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刹泄,“玉大人外里,你說(shuō)我怎么就攤上這事√厥” “怎么了盅蝗?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)姆蘸。 經(jīng)常有香客問(wèn)我墩莫,道長(zhǎng)芙委,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任狂秦,我火速辦了婚禮灌侣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裂问。我一直安慰自己侧啼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布愕秫。 她就那樣靜靜地躺著慨菱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戴甩。 梳的紋絲不亂的頭發(fā)上符喝,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音甜孤,去河邊找鬼协饲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛缴川,可吹牛的內(nèi)容都是我干的茉稠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼把夸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼而线!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起恋日,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤膀篮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后岂膳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體誓竿,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年谈截,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筷屡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簸喂,死狀恐怖毙死,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喻鳄,我是刑警寧澤规哲,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站诽表,受9級(jí)特大地震影響唉锌,放射性物質(zhì)發(fā)生泄漏隅肥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一袄简、第九天 我趴在偏房一處隱蔽的房頂上張望腥放。 院中可真熱鬧,春花似錦绿语、人聲如沸秃症。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)种柑。三九已至,卻和暖如春匹耕,著一層夾襖步出監(jiān)牢的瞬間聚请,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工稳其, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驶赏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓既鞠,卻偏偏與公主長(zhǎng)得像煤傍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱蛋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348