在面向?qū)ο笳Z言程序中袍榆,我們的程序在運(yùn)行中會創(chuàng)建很多對象最岗,程序會為對象在內(nèi)存中開辟一段空間并分配好內(nèi)存地址烙常,當(dāng)對象使用結(jié)束后磷蜀,需要釋放占用的內(nèi)存空間召耘,釋放對象內(nèi)存的機(jī)制就叫垃圾回收機(jī)制(Garbage Collection,GC)褐隆。在C語言中污它,動態(tài)分配內(nèi)存用 malloc() 函數(shù),釋放內(nèi)存用 free() 函數(shù)庶弃,而C++中衫贬,我們則使用運(yùn)算符 new 和 delete 來管理內(nèi)存,這樣雖然能靈活有效的申請和釋放內(nèi)存歇攻,但是對程序員來說固惯,有時(shí)候使一種負(fù)擔(dān),而Java的垃圾回收機(jī)制則很好的解決了這一問題缴守。
一葬毫、垃圾回收機(jī)制:
JVM自動不定時(shí)去堆內(nèi)存中清理不可達(dá)對象。不可達(dá)的對象并不會馬上就會直接回收屡穗,垃圾收集器在一個Java程序中的執(zhí)行是自動的贴捡,不能強(qiáng)制執(zhí)行,即使程序員能明確地判斷出有一塊內(nèi)存已經(jīng)無用了村砂,是應(yīng)該回收的烂斋,程序員也不能強(qiáng)制垃圾收集器回收該內(nèi)存塊。程序員唯一能做的就是通過調(diào)用System.gc 方法來"建議"執(zhí)行垃圾收集器础废,但其是否可以執(zhí)行源祈,什么時(shí)候執(zhí)行卻都是不可知的。這也是垃圾收集器的最主要的缺點(diǎn)色迂。當(dāng)然相對于它給程序員帶來的巨大方便性而言香缺,這個缺點(diǎn)是瑕不掩瑜的。
1. 不可達(dá)對象:?對象沒有被引用歇僧,獲知對象沒有存活图张。
2. finalize方法:
Java在垃圾收集器將對象從內(nèi)存中清除出去前,使用finalize()方法做必要的清理工作诈悍。該方法在Object類中定義祸轮,因此所有的類都繼承了它。子類覆蓋finalize()方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作侥钳。finalize方法是在垃圾收集器刪除對象之前對這個對象調(diào)用的适袜。
3. 新生代和老年代:
堆內(nèi)存被劃分成兩個不同的區(qū)域:新生代 ( Young )、老年代 ( Old )舷夺。
新生代 ( Young ) 又被劃分為三個區(qū)域:Eden苦酱、From Survivor(S0)售貌、To Survivor(S1)。S0區(qū)和S1區(qū)內(nèi)存大小相等疫萤。
新生代:剛new出不久的對象存放在新生代中颂跨,存放不經(jīng)常被使用的對象。
老年代:存放比較活躍的對象扯饶,存放經(jīng)常被引用的對象恒削。
垃圾回收機(jī)制在新生代回收的次數(shù)比較頻繁,而在老年代回收的次數(shù)相對較少尾序。而且一般情況下钓丰,老年代的內(nèi)存空間大于新生代的內(nèi)存空間。
二每币、判斷對象存活的方法:
1.引用計(jì)數(shù)法:
給對象中添加一個引用計(jì)數(shù)器携丁,每當(dāng)有一個地方引用它時(shí),計(jì)數(shù)器值加1脯爪;當(dāng)引用失效時(shí)则北,計(jì)數(shù)器值減1矿微。任何時(shí)刻計(jì)數(shù)器值為0的對象就是不可能再被使用的痕慢。當(dāng)對象計(jì)數(shù)器的值大于15時(shí),會被存放到堆內(nèi)存的老年代中涌矢,當(dāng)對象的值大于0小于15時(shí)則存放在新生代中掖举。因其很難解決對象之間相互循環(huán)引用的問題,所以該算法逐漸被淘汰娜庇,而別很少出現(xiàn)在主流的Java虛擬機(jī)中塔次。
2.根搜索算法:
根搜索算法的基本思路就是通過一系列名為”GC Roots”的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索名秀,搜索所走過的路徑稱為引用鏈(Reference Chain)励负,當(dāng)一個對象到GC Roots沒有任何引用鏈相連時(shí),則證明此對象是不可用的匕得。
在Java語言中继榆,可以作為GCRoots的對象包括下面幾種:
(1). 棧(棧幀中的局部變量區(qū),也叫做局部變量表)中引用的對象汁掠。
(2). 方法區(qū)中的類靜態(tài)屬性引用的對象略吨。
(3). 方法區(qū)中常量引用的對象。
(4). 本地方法棧中JNI(Native方法)引用的對象考阱。
三翠忠、垃圾回收策略:
1、標(biāo)記清除算法:
標(biāo)記階段:遍歷堆乞榨,將不可達(dá)對象標(biāo)記為1秽之,可達(dá)對象標(biāo)記為0当娱。
清除階段:遍歷堆,逐個把標(biāo)記為1的不可達(dá)對象回收政溃。
缺點(diǎn):由于堆內(nèi)存空間不連續(xù)趾访,所以逐個回收對象時(shí)會產(chǎn)生內(nèi)存空間碎片化,而且效率低董虱。
應(yīng)用場景:用于對象存活周期較長的老年代扼鞋。
2、復(fù)制算法:
復(fù)制算法的基本思想是JVM一開始就會將可用內(nèi)存分為大小相等的兩塊:from域(S0區(qū))和to域(S1區(qū))愤诱。每次只是使用from域云头,to域則空閑著。當(dāng)from域內(nèi)存不夠了淫半,開始執(zhí)行GC操作溃槐,這個時(shí)候,會把from域存活的對象拷貝到to域科吭,然后直接把from域進(jìn)行內(nèi)存清理昏滴。
應(yīng)用場景:新生代。在新生代中对人,內(nèi)存會被分為Eden區(qū)谣殊、S0區(qū)和S1區(qū)。剛new出來的對象剛開始會被存放在Eden區(qū)牺弄,當(dāng)Eden區(qū)內(nèi)存滿后姻几,觸發(fā)新生代的GC操作,把可達(dá)對象拷貝至S0區(qū)势告,清除Eden區(qū)中的所有對象蛇捌,當(dāng)Eden區(qū)再次觸發(fā)GC操作時(shí),會掃描Eden區(qū)和S0區(qū)域咱台,對兩個區(qū)域進(jìn)行垃圾回收络拌,經(jīng)過這次回收后還存活的對象,則直接復(fù)制到S1區(qū)域回溺,并將Eden和From區(qū)域清空春贸;當(dāng)后續(xù)Eden又發(fā)生GC回收時(shí),會對Eden和S1區(qū)域進(jìn)行垃圾回收馅而,存活的對象復(fù)制到S0區(qū)域祥诽,并將Eden和S1區(qū)清空;如此交換15次(由JVM參數(shù)MaxTenuringThreshold決定,這個參數(shù)默認(rèn)是15)瓮恭,最終如果還是存活雄坪,就存入到老年代。
優(yōu)缺點(diǎn):性能高屯蹦,解決了碎片化問題维哈,但是S0和S1區(qū)總有一塊內(nèi)存空白绳姨,造成內(nèi)存空間浪費(fèi)。
應(yīng)用場景:新生代阔挠。
3飘庄、標(biāo)記壓縮算法:
在標(biāo)記清除算法的基礎(chǔ)上,將對象進(jìn)行排序购撼,使不可達(dá)對象盡可能地排序在一起跪削,GC操作時(shí)就可整段刪除不可達(dá)對象,從而解決標(biāo)記清除算法中產(chǎn)生碎片化的問題迂求。
4碾盐、分代算法:
根據(jù)對象的存活周期的不同將內(nèi)存劃分成幾塊,新生代和老年代揩局,這樣就可以根據(jù)各個年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ê辆痢P律捎脧?fù)制算法,老年代使用標(biāo)記壓縮算法凌盯。