在Java中怎麼可以看一個對象是不是垃圾對象

在Java中怎麼可以看一個對象是不是垃圾對象

如何判斷一個對象是不是垃圾對象

第一、引用計數法

引用計數描述的算法爲:|

給每一個對象增加一個引用計數器,每當有一個地方引用它時,計數器就+1;當引用失效時,計數器就-1;
何時刻計數器爲0的對象就是不能再被使用的,即對象已"死"

引用計數法實現簡單,判定效率也比較高,在大部分情況下都是一個不錯的算法。

但是,在主流的JVM中沒有選用引用計數法來管理內存,最主要的原因就是引用計數法無法解決對象的
循環引用問題

public class Test {
    public Object instance = null;
    private static int _1MB = 1024 * 1024;
    private byte[] bigSize = new byte[2 * _1MB];

    public static void testGC() {
        Test test1 = new Test();
        Test test2 = new Test();
        test1.instance = test2;
        test2.instance = test1;
        test1 = null;
        test2 = null;
        //強制進行垃圾回收
        System.gc();
    }

    public static void main(String[] args) {
        testGC();
    }
}

注意,在Java中垃圾回收會回收兩個互相引用的對象的,因爲Java虛擬機不是用的引用計數算法來判斷對象是否死亡。

第二、可達性分析算法

可達性分析算法也是可以判斷對象是否死亡

先來說一下什麼是GC roots?

GC roots就是來判斷是否爲垃圾對象的,通俗一點來說:就是GC roots的對象以及被GC roots 引用的對象都不是垃圾對象,其他的對象都是垃圾對象。
此算法的核心思想爲 : 通過一系列列稱爲"GC Roots"的對象作爲起始點,從這些節點開始向下搜索,搜索
走過的路徑稱之爲"引用鏈",當一個對象到GC Roots沒有任何的引用鏈相連時(從GC Roots到這個對象不可達)時,證明此對象是不可用的

哪些對象可以作爲GC roots對象呢?

1.虛擬機棧(棧幀中的本地變量表)中引用的對象
2.方法區中類靜態屬性引用的對象
3.方法區中常量引用的對象
4.本地方法棧中JNI(Native方法)引用的對象|

注意並不是棧中的引用可以作爲GC roots,而是棧中引用所指向的對象可以作爲GC roots對象

在這裏插入圖片描述

第三、四種引用

在Java中引用分爲四種引用:強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)和虛引用(Phantom Reference)四種,這四種引用的強度依次遞減

1、強引用

強引用指的是在程序代碼之中普遍存在的,類似於"Object obj = new Object()"這類的引用,只要強引用還存在,垃圾回收器永遠不會回收掉被引用的對象實例
只要被GC roots 直接引用的或者間接引用的都是強引用

2、軟引用

軟引用是用來描述一些還有用但不是必須的對象。對於軟引用關聯着的對象,在系統將要發生內存溢出之前,會把這些對象列入回收範圍之中進行第二次回收。如果這次回收還是沒有足夠的內存,纔會拋出內存溢出異常。在JDK1.2之後,提供了了SoftReference類來實現軟引用。

簡單的說:就是第一次進行垃圾回收之後,內存還是不夠的情況下,會進行二次回收,第二次會把軟引用的對象進行回收,如果第二次回收之後,內存還是不夠,就會拋出異常。

3、弱引用

弱引用也是用來描述非必需對象的。但是它的強度要弱於軟引用。被弱引用關聯的對象只能生存到下一次垃圾回收發生之前。當垃圾回收器開始進行工作時,無論當前內容是否夠用,都會回收掉只被弱引用關聯的對象。在JDK1.2之後提供了了WeakReference類來實現弱引用。

簡單的說:被弱引用引用的對象每次垃圾回收都會被回收掉

4,虛引用

虛引用:最弱的一種引用關係。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。爲一個對象設置虛引用的唯一目的就是能在這個對象被收集器器回收時收到一個系統通知。在JDK1.2之後,提供了了PhantomReference類來實現虛引用。

注意:虛引用的對象被回收時,並不會回收分配到直接內存,所以就會將虛引用放置引用隊列中,會有一個專門的線程會定時查看引用隊列有沒有引用,如果有就會釋放該虛引用的內存地址,從而釋放直接內存。

還有一種就是重寫Object類的finallized()方法(終結器引用)

終結器引用:當對象沒有被強引用引用時,並且該對象重寫了finallized()方法,該對象並不會直接被回收,而是將該引用放到引用隊列中,就會有一個Finallizer線程來進行處理,但是該線程的優先級太低,一般被系統調度的機率小,如果還沒釋放對象之前,該對象被重新引用時,該引用就不會在引用隊列中,該線程進行清除時,就會調用該對象的finallized()方法,這時候對象纔是真正的死亡。

注意:finallized()方法只會被調用一次。

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