哪些內(nèi)存需要回收
? java堆中存放著幾乎所有對(duì)象實(shí)例,垃圾收集器在堆進(jìn)行回收前豆村,判斷哪些對(duì)象還存活著。
1.引用計(jì)數(shù)算法
? ? ? 給對(duì)象添加一個(gè)引用計(jì)數(shù)器,當(dāng)有一個(gè)地方引用它立膛,計(jì)數(shù)器加1,引用失效時(shí)梯码,計(jì)數(shù)器就減1宝泵,計(jì)數(shù)器為0的對(duì)象就不可能被使用。優(yōu)點(diǎn):算法簡(jiǎn)單轩娶,效率高儿奶,但當(dāng)存貨對(duì)象相互引用就解決不了。所以Java中GC沒(méi)有采用引用計(jì)數(shù)法來(lái)管理內(nèi)存
2.可達(dá)性分析算法
? ? ?以GC Roots對(duì)象作為起始點(diǎn)鳄抒,從這些節(jié)點(diǎn)依次向下搜索闯捎,如果當(dāng)前對(duì)象到GC Roots沒(méi)有任何路徑相連時(shí),那么當(dāng)前對(duì)象沒(méi)有引用嘁酿。
? ? 可做GC Roots的對(duì)象1.java虛擬機(jī)棧中引用的對(duì)象 2.本地方法棧中引用的對(duì)象 3.方法區(qū)中的常量引用的對(duì)象 4.方法區(qū)中靜態(tài)屬性引用的對(duì)象隙券。當(dāng)對(duì)象不可達(dá),并不是宣告對(duì)象死亡闹司,還有對(duì)象進(jìn)行最后自我救贖--finalize娱仔。java允許使用finalize方法在垃圾收集器將對(duì)象從內(nèi)存中清楚之前做必要清理工作。這個(gè)操作中如果對(duì)象被重新引用游桩,對(duì)象就可以活過(guò)來(lái)了牲迫。
? ? ?判斷對(duì)象是否有必要執(zhí)行該方法主要有以下兩個(gè)依據(jù):對(duì)象有沒(méi)有覆蓋finalize方法;對(duì)象已覆蓋finalize方法借卧,檢查finalize方法是否被虛擬機(jī)調(diào)用過(guò)盹憎,如果已被調(diào)用,就不需要再次執(zhí)行铐刘。
何時(shí)回收
? ? young gc觸發(fā)條件似乎要簡(jiǎn)單很多陪每,當(dāng) eden 區(qū)的內(nèi)存不夠時(shí),就會(huì)觸發(fā)young gc
full gc
1. old gen 空間不足
? ? ? ?當(dāng)創(chuàng)建一個(gè)大對(duì)象镰吵、大數(shù)組時(shí)檩禾,eden 區(qū)不足以分配這么大的空間,會(huì)嘗試在old gen 中分配疤祭,如果這時(shí) old gen 空間也不足時(shí)盼产,會(huì)觸發(fā) full gc,為了避免上述導(dǎo)致的 full gc勺馆,調(diào)優(yōu)時(shí)應(yīng)盡量讓對(duì)象在 young gc 時(shí)就能夠被回收戏售,還有不要?jiǎng)?chuàng)建過(guò)大的對(duì)象和數(shù)組侨核。
2. 統(tǒng)計(jì)得到的 young gc 晉升到 old gen的對(duì)象平均總大小大于old gen 的剩余空間
? ? ? ?當(dāng)準(zhǔn)備觸發(fā)一次 young gc時(shí),會(huì)判斷這次 young gc 是否安全灌灾,這里所謂的安全是當(dāng)前老年代的剩余空間可以容納之前 young gc 晉升對(duì)象的平均大小搓译,或者可以容納 young gen 的全部對(duì)象,如果結(jié)果是不安全的紧卒,就不會(huì)執(zhí)行這次 young gc侥衬,轉(zhuǎn)而執(zhí)行一次 full gc
3. perm gen 空間不足
? ? ?如果有perm gen的話,當(dāng)系統(tǒng)中要加載的類跑芳、反射的類和調(diào)用的方法較多,而且perm gen沒(méi)有足夠空間時(shí)直颅,也會(huì)觸發(fā)一次 full gc
4. ygc出現(xiàn) promotion failure
? ? ? promotion failure 發(fā)生在 young gc 階段博个,即 cms 的 ParNewGC,當(dāng)對(duì)象的gc年齡達(dá)到閾值時(shí)功偿,或者 eden 的 to 區(qū)放不下時(shí)盆佣,會(huì)把該對(duì)象復(fù)制到 old gen,如果 old gen 空間不足時(shí)械荷,會(huì)發(fā)生 promotion failure共耍,并接下去觸發(fā)full gc
如何回收
標(biāo)記-清除算法
? ? ?標(biāo)記清除算法分為”標(biāo)記“和”清除“兩個(gè)階段:首先標(biāo)記處所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象吨瞎。
它的不足有兩個(gè):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ù)制算法
? ? ? 為了解決效率問(wèn)題遗淳,”復(fù)制“算法出現(xiàn)了,將可用的內(nèi)存劃分為兩塊心傀,每次只使用其中一塊地熄, 當(dāng)這一塊的內(nèi)存用完了岩齿,就將還存活著的對(duì)象復(fù)制到另一塊上面,然后再把已使用過(guò)的內(nèi)存空間一次清理掉。這樣就不用考慮內(nèi)存碎片等復(fù)雜情況〈慌ǎ現(xiàn)在的商業(yè)虛擬機(jī)都采用這這種收集算法來(lái)回收新生代。根據(jù)研究表明雳窟,新生代中98%的對(duì)象都是”朝生夕死“的表窘,所以新生代中將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間(from和to),每次使用Eden和其中一塊Survivor堕油,當(dāng)回收時(shí)潘飘,將Eden和剛才用過(guò)的Survivor中還存活的對(duì)象一次性的復(fù)制到另外一個(gè)Survivor空間上肮之,最后清理掉Eden和剛才用過(guò)的Survivor空間。
? ? ? Hotspot虛擬機(jī)默認(rèn)使用Eden和Survivor的大小比例是8:1卜录,也就是Eden占8戈擒,form和to各占1.當(dāng)Survivor空間不夠的時(shí)候,需要依賴?yán)夏甏M(jìn)行分配擔(dān)保艰毒。在發(fā)生Minor GC之前筐高,虛擬機(jī)會(huì)檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象的總空間,如果大于丑瞧,則此次Minor GC是安全的柑土;如果小于,則虛擬機(jī)會(huì)查看HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗绊汹。如果HandlePromotionFailure=true稽屏,那么會(huì)繼續(xù)檢查老年代最大可用連續(xù)空間是否大于歷次晉升到老年代的對(duì)象的平均大小,如果大于西乖,則嘗試進(jìn)行一次Minor GC狐榔,但這次Minor GC依然是有風(fēng)險(xiǎn)的;如果小于或者HandlePromotionFailure=false获雕,則改為進(jìn)行一次Full GC薄腻。
標(biāo)記-整理算法
? ? ?標(biāo)記整理算法的“標(biāo)記”過(guò)程和標(biāo)記-清除算法一致,只是后面并不是直接對(duì)可回收對(duì)象進(jìn)行整理届案,而是讓所有存活的對(duì)象都向一段移動(dòng)庵楷,然后直接清理掉端邊界以外的內(nèi)存。
分代收集算法
? ? ? 當(dāng)前商業(yè)虛擬機(jī)的垃圾收集都采用”分代收集“算法萝玷,其主要思想是將Java堆分為新生代和老年代嫁乘,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適合的收集算法。
? ? ? 在新生代采用復(fù)制算法球碉,上面已經(jīng)講過(guò)了蜓斧。而老年代因?yàn)閷?duì)象存活率高,沒(méi)有額外空間為它進(jìn)行分配擔(dān)保睁冬,就必須使用”標(biāo)記清理“或者”標(biāo)記整理“算法來(lái)進(jìn)行回收挎春。
面試題
1.你知道哪幾種垃圾收集器,各自的優(yōu)缺點(diǎn)豆拨,重點(diǎn)講下cms直奋,包括原理,流程施禾,優(yōu)缺點(diǎn)脚线?
? ? ? 串行垃圾收集器:收集時(shí)間長(zhǎng),停頓時(shí)間久(單線程收集器弥搞,它進(jìn)行垃圾收集時(shí)邮绿,暫停其他所有工作的線程渠旁,直到收集結(jié)束)
? ? ? 并發(fā)垃圾收集器:碎片空間多(使用多線程來(lái)通過(guò)掃描并壓縮堆,可以大幅度壓縮停頓時(shí)間)
? ? ? CMS收集器:主要基于標(biāo)記-清除算法實(shí)現(xiàn)船逮,使用多線程算法去掃描并發(fā)現(xiàn)未使用的對(duì)象進(jìn)行回收,初始標(biāo)記(標(biāo)記GC Roots直接關(guān)聯(lián)的對(duì)象)顾腊、并發(fā)標(biāo)記、并發(fā)預(yù)清理挖胃、并發(fā)清除杂靶、并發(fā)重置.
? ? ? G1收集器:主要步驟:初始標(biāo)記,并發(fā)標(biāo)記酱鸭,重新標(biāo)記吗垮,復(fù)制清除(整理)它是“標(biāo)記-整理”算法實(shí)現(xiàn)的收集器
? ? ? CMS的缺點(diǎn)是對(duì)cpu的要求比較高。G1是將內(nèi)存化成了多塊凹髓,所有對(duì)內(nèi)段的大小有很大的要求
? ? ? CMS是清除抱既,所以會(huì)存在很多的內(nèi)存碎片。G1是整理扁誓,所以碎片空間較小
2..垃圾回收算法
? ? 引用計(jì)數(shù),增加一個(gè)字段來(lái)標(biāo)記當(dāng)前應(yīng)用次數(shù)蚀之,引用計(jì)數(shù)為0就可以GC蝗敢,但不能解決循環(huán)引用的問(wèn)題
? ? 可達(dá)性:通過(guò)一系列GC Root的對(duì)象作為起點(diǎn),向下搜索足删,搜索所有沒(méi)有與當(dāng)前對(duì)象GC ROOT有引用關(guān)系的對(duì)象寿谴,這是對(duì)象就可以GC