Java基礎一 Java對象的引用

一.Java 強引用 軟引用 弱引用 虛引用的使用場景以及系統調用時機

Java的引用強引用直接使用了對象的地址,軟引用 弱引用 虛引用 都在引用對象之間隔了一層通過這些特殊的對象間接引用了我們需要的對象。

1.強引用:

Object object = new Object();

object 這個Object類型的變量直接引用了new Object() 這個類型的在內存中開闢的這塊地址空間的地址。這是我們常見的編碼方式。使用場景有:方法的局部變量,jni變量,類變量,概括起來就是GC ROOT 可達的都是強引用。

1.object如果前面加上static修飾那麼這個Object 類型的變量就會在常量區定義那麼會一直引用指着這塊開闢的地址內存不會釋放。

2.object這個變量在棧內引用已經執行完了並且沒有其他地方引用這個地址時這塊地址的引用數爲0那麼這塊地址可以被釋放。

3.只要有引用在,垃圾回收器永不處理,jvm寧願自己崩了一般報(OutOfMemoryError)錯誤,也不去回收這個這類對象使用的內存。所以會造成內存泄漏和內存溢出。

4.源代碼

class FinalReference<T> extends Reference<T> {

    public FinalReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

2.軟引用:

Objext obect = new Object();

SoftReference<Object> sfObject = new SoftReference<Object>(obj);

sfObject.get();//有時候會返回null

1.軟引用即在生成的對象和產生的地址之上再封裝一層。我們需要使用這個對象時通過軟引用間接的獲取到這個對象的使用。

2.object的釋放在jvm內存不足時object指定的內存塊釋放。

3.軟用可以用在程序中的緩存功能的實現,比如圖片緩存,對象緩存等等。

4.在Android中 SoftReference 或者 WeakReference做圖片緩存是不推薦的,因爲Android內存小會更頻繁的對於這些引用的對象進行回收,回收後又會頻繁的對這些對象開闢內存空間。所以Android官方推薦最新的解決辦法,這個類包含在android-support-v4包中,是採用LruCache以及DiskLruCache。Android中可以使用SoftReference 或者WeakReference 用在把上下文傳入靜態工具中以免造成activity內存泄漏。後續講這類工具時在細分講解。

5.源代碼

public class SoftReference<T> extends Reference<T> {

    /**
     * Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /**
     * Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    /**
     * Creates a new soft reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new soft reference will refer to
     */
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }

    /**
     * Creates a new soft reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new soft reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     *
     */
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

6.在新建SoftReference對象和調用SoftReference.get時都會使timestamp更新爲clock的值。而clock代表的是上次gc的時間。 

SoftRefLRUPolicyMSPerMB默認爲1000,即1s。代表每1MB空閒空間大小SoftReference保留1s。 

-XX:SoftRefLRUPolicyMSPerMB      

設置每兆堆空閒空間中SoftReference的存活時間,默認值是1s 。(softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap)

3.弱引用:

Object object = new Object();

WeakReference<Object> wfObect = new WeakReference<Object>(object);

wfObject.get();//有時返回爲null

wfObject.isEnQueued();//返回引用狀態  返回是否被垃圾回收器標記爲即將回收的垃圾

1.弱引用是在第二次垃圾回收時回收,短時間內通過弱引用取對應的數據,可以取到,當執行過第二次垃圾回收時,將返回null。
2.弱引用主要用於監控對象是否已經被垃圾回收器標記爲即將回收的垃圾,可以通過弱引用的isEnQueued方法返回對象是否被垃圾回收器標記。

3.只具有弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。

4.源代碼

public class WeakReference<T> extends Reference<T> {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

4.虛引用:

Object object = new Object();
PhantomReference<Object> pfObject = new PhantomReference<Object>(object);

pfObject.get() //永遠返回爲null

pf.isEnQueued();//返回是否從內存中已經刪除
1.虛引用是每次垃圾回收的時候都會被回收,通過虛引用的get方法永遠獲取到的數據爲null,因此也被成爲幽靈引用。
2.垃圾回收器掃描時即回收內存的使用。

3.虛引用主要用於檢測對象是否已經從內存中刪除。

4.源代碼

public class PhantomReference<T> extends Reference<T> {

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }

    /**
     * Creates a new phantom reference that refers to the given object and
     * is registered with the given queue.
     *
     * <p> It is possible to create a phantom reference with a <tt>null</tt>
     * queue, but such a reference is completely useless: Its <tt>get</tt>
     * method will always return null and, since it does not have a queue, it
     * will never be enqueued.
     *
     * @param referent the object the new phantom reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

 

二.源碼解析

1.首先我們看看Java中引用類在哪個文件夾裏。這裏使用的jdk版本是jdk1.8

 

2.對象引用概述

在jdk1.2以前的版本,對象引用類型單一隻有強引用類型,在1.2版本以後對引用類型做了擴充,把引用對象做了四個級別的設置更好的對對象的生命週期進行管控。這4種級別由高到低依次爲:強引用、軟引用、弱引用和虛引用。

3.對象的生命週期和回收隊列

1.所有的對象引用都繼承了在package java.lang.ref包下面的 Reference<T> 類。Reference類首先把內存分爲4種狀態Active,Pending,Enqueued,Inactive。

.Active 一般來說new出來的對象一開始設置的狀態是active

.Pending 待定中,指快放入回收隊列的對象

.Enqueued 就是對象的內存已經被gc回收了

.Inactive最終狀態,不可改變對象

2.ReferenceQueue 引用隊列,在檢測到適當的可到達性更改後,垃圾回收器將已註冊的引用對象添加到隊列中,ReferenceQueue實現了入隊(enqueue)和出隊(poll),還有remove操作,內部元素head就是泛型的Reference。

 

4.對象使用完的垃圾回收

1.回收的區域

jvm虛擬機劃分使用的內存區域有堆區,棧區,靜態常量區,方法區等。新建的對象都放在堆區,因此需要回收的區域就是分配建立對象的堆區。

2.回收的對象

1.gc root 不在引用的對象。即現在程序不需要使用的對象需要釋放掉使用的內存

3.回收的方法

1.可達性分析 從gc root這類對象開始,向下搜索。

gc root 的種類:

Class:由系統的類加載器加載的類對象 
Static Fields 
Thread:活着的線程 
Stack Local: java方法的局部變量或參數 
JNI Local: JNI方法中的局部引用 
JNI Global: 全局的JNI引用 
Monitor used: 用於同步的監控對象
 

2.引用計數分析

 

5.Java的分代回收機制

1.將對象依據使用時長進行分類,分成新生類,中年類,老年類等。

 

6.leakscannary的原理

 

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