垃圾回收之對象是否可回收

一般去面試經常會遇到垃圾回收相關的問題,最近做了個小結,下面就來記錄並分享下垃圾回收相關的東西:

1)引用計數法
給對象添加一個引用計數器,每當有一個地方引用它時,計數器就+1;當引用失效時,計數器就-1;當計數器爲0時,則表示這個對象是不可再被使用的。
2)根搜索算法
通過一系列名爲“GC Root”的對象作爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Root沒有任何引用鏈相連即從GC Root到這個對象不可達時,則證明此對象是不可用的。
但是在根搜索算法不可達的對象也並非是非回收不可的,這是它們暫時處於暫存的階段,要真正能夠回收一個對象,至少需要經歷兩次標記的過程:如果對象在進行根搜索後發現沒有雨GC Root相連接的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選的條件是此對象是否有必要執行finialize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法以及被虛擬機調用過,虛擬機將這兩種情況都視爲不可被回收。
如果某個對象被判定爲需要執行finialize()方法,那麼這個對象將會被放置在一個名爲F-Queue的隊列之中,並在稍後由一條虛擬機自動建立、低優先級的Finalizer線程去執行。這裏所謂的“執行”是指虛擬機會觸發這個方法,但並不會承諾會等待它運行結束。這樣做的原因是:如果一個對象在finialize()方法中執行緩慢,或者發生了死循環等情況時,將很有可能會導致F-Queue隊列中的其他對象永久處於等待狀態,甚至導致整個內存回收系統崩潰。finialize()方法是對象逃脫死亡命運的最後一次機會,稍後GC 將對F-Queue中的對象進行第二次小規模的標記,如果對象要做finialize()中成功拯救自己——只要重新與引用鏈上的任何一個對象建立關聯即可,譬如通過this關鍵字賦值給某個類變量或對象的成員變量,那麼在第二次標記時它將被移除出“即將回收”的集合;如果對象這個時候還沒有逃脫,則離回收也就不遠了。
3)引用
a、強引用
只要強引用還存在,垃圾收集器永遠不會回收掉引用的對象。
b、軟引用
軟引用用來描述一些還有用但非必須對象。對於軟引用關聯着的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進回收範圍之中並進行第二次回收。
c、弱引用
弱引用也是用來描述非必須對象的,但是它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集器發生之前。(可用WeakReference類來實現弱引用)
d、虛引用
虛引用也稱爲幽靈引用或者幻影引用,它是最弱的一種引用關係。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。
4)回收方法區
很多人認爲方法區(或者HotSpot虛擬機中的永久代)是沒有垃圾收集的,Java虛擬機規範中確實說過可以不要求虛擬機在方法區實現垃圾收集器,而且在方法區進行垃圾收集的“性價比”一般較低:在堆中,尤其是在新生代中,常規應用進行一次垃圾回收一般可以回收70%~95%的空間,而永久代的垃圾收集效率遠低於此。
永久代的垃圾收集主要分爲兩部分內容:廢棄常量和無用的類。回收廢棄常量與回收Java堆中的對象非常類似。以常量池中字面量的回收爲例,假如一個字符串“abc”以及進入了常量池中,但是當前系統沒有任何一個String對象是叫做“abc”的,換句話說是沒有任何String對象引用常量池中的“abc”常量,也沒有其他地方引用了這個字面量,如果在這時發生內存回收,而且必要的話,這個“abc”常量就會被系統“請”出常量池。常量池中的其他類、接口、方法、字段的符號引用也與此類似。
判斷類無用的條件如下所示:
1)該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
2)加載該類的ClassLoader已經被回收
3)該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章