垃圾收集器在對(duì)堆進(jìn)行垃圾回收前,第一件事就是判斷這些對(duì)象是否存活著谋逻。判斷是否存活著有兩種算法:引用計(jì)數(shù)算法和可達(dá)性分析算法
引用計(jì)數(shù)算法
給每個(gè)對(duì)象添加一個(gè)引用計(jì)數(shù)器导帝,該對(duì)象被N個(gè)引用所引用悔叽,計(jì)數(shù)器值為N。引用增加時(shí),值+1凄鼻,引用失效時(shí)肢础,值-1。當(dāng)值為0的時(shí)候肴掷,說(shuō)明該對(duì)象上所有的引用皆已失效敬锐,可以認(rèn)為該對(duì)象不再存活。
這個(gè)算法挺好理解的呆瞻,但有一個(gè)缺點(diǎn)台夺,無(wú)法解決相互引用對(duì)方的情況。如objA和objB都有字段instance痴脾,使objA.instance=objB及objB.instance=objA并且objA=null及objB=null颤介,按理說(shuō)這兩個(gè)對(duì)象應(yīng)該失效,但objA的instance又引用著對(duì)象B赞赖,objB的instance又引用著對(duì)象A滚朵,導(dǎo)致計(jì)數(shù)器不為0,無(wú)法回收前域。
可達(dá)性算法
這是比較主流的算法始绍。通過(guò)GC Roots 作為起始點(diǎn),往下搜索话侄,搜索走過(guò)的路徑被稱為引用鏈(Reference Chain)亏推,當(dāng)所有引用鏈遍歷完以后学赛,沒出現(xiàn)在任何一個(gè)引用鏈上的對(duì)象則被視為不可用。以下對(duì)象可作為GC Roots:
- 虛擬機(jī)棧(本地變量表)中引用的對(duì)象
- 方法區(qū)靜態(tài)屬性引用的對(duì)象
- 方法區(qū)中常量引用的對(duì)象
- 本地方法棧中Native方法引用的對(duì)象
如上圖所示object1吞杭、object2盏浇、object3都在以GC Roots為起始點(diǎn)的引用鏈上,這三個(gè)引用的對(duì)象則存活芽狗。object4绢掰、object5則沒在任意一個(gè)以GC Roots為起始點(diǎn)的引用鏈上,這兩個(gè)引用的對(duì)象則失效童擎。
即使是可達(dá)性算法不可達(dá)的對(duì)象滴劲,也不一定就會(huì)被立即回收,會(huì)給予一次機(jī)會(huì)顾复。第一次檢查不可達(dá)班挖,會(huì)對(duì)其進(jìn)行標(biāo)記并進(jìn)行一次篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法芯砸,如果沒有覆蓋finalize()萧芙,或finalize()已被調(diào)用過(guò),則被認(rèn)為沒有必要執(zhí)行假丧。
如果被判斷需要執(zhí)行finalize()方法双揪,則將對(duì)象放入F-Queue的隊(duì)列中,并在之后由一個(gè)虛擬機(jī)自動(dòng)創(chuàng)建的包帚、低優(yōu)先級(jí)的FinaLizer線程去執(zhí)行它渔期。如果一個(gè)對(duì)象在執(zhí)行finalize()方法時(shí)運(yùn)行緩慢或者死循環(huán),則其他對(duì)象會(huì)永遠(yuǎn)等待甚至造成內(nèi)存回收系統(tǒng)的崩潰渴邦。
finalize()是對(duì)象唯一可以自救的機(jī)會(huì)疯趟,若在finailze()方法將對(duì)象重新加入引用鏈中,則可以在第二次標(biāo)記中被移除“即將回收”的集合几莽。否則迅办,錯(cuò)過(guò)了自救的機(jī)會(huì)宅静,在第二次標(biāo)記時(shí)就真的被銷毀了章蚣。
注:finalize()在兩次標(biāo)記中只會(huì)被調(diào)用一次。并不鼓勵(lì)覆蓋finalize()方法姨夹,不確定性大纤垂,很容易失去控制,作為了解即可磷账。