java.lang.ref.Reference源代碼分析

自己想學習下java.lang.ref這個package下面的源碼,在網上找了找一些帖子看了看,感覺對自己的幫助很大,打算自己總結下java.lang.ref這個包,以及垃圾回收的機制,期待對自己有幫助.

一,引用實例有4個狀態,Active,Pending,Enqueued,Inactive.jdk源碼的解釋如下:

  • Active: Subject to special treatment by the garbage collector. Some time after the collector detects that the reachability of the referent has changed to the appropriate state, it changes the instance’s state to either Pending or Inactive, depending upon whether or not the instance was registered with a queue when it was created. In the former case it also adds the instance to the pending-Reference list. Newly-created instances are Active.
      激活:垃圾回收器特別處理的主題。有時候在回收器檢測到被引用(對象)的可達性被改變成適當 的狀態,它會把實例的狀態改變成等待狀態或者未激活狀態,這取決於實例是否被一個隊列註冊當 它被創建。在前一種情況下(等待狀態),它也往等待-引用集合增加實例。
  • Pending: An element of the pending-Reference list, waiting to be enqueued by the Reference-handler thread. Unregistered instances are never in this state.
      等待:一個等待-引用集合裏的元素,等待被引用處理線程放入隊列中。
      未註冊的實例永遠不會在這個狀態
  • Enqueued: An element of the queue with which the instance was registered when it was created. When an instance is removed from its ReferenceQueue, it is made Inactive. Unregistered instances are never in this state.
      入隊:實例被創建的時候被登記註冊成一個隊列的元素。當一個實例從引用隊列中刪除,它變成非激活狀態。未註冊的實例永遠不會在這個狀態。
  • Inactive: Nothing more to do. Once an instance becomes Inactive its state will never change again.
      非激活:不會再做什麼。一旦一個實例成爲非激活的,它的狀態永遠不會被改變。
      The state is encoded in the queue and next fields as follows:

二,狀態在隊列裏被處理並且每個狀態所表現的屬性如下:

  • Active: queue = ReferenceQueue with which instance is registered, or
    ReferenceQueue.NULL if it was not registered with a queue; next =
    null.
    激活:queue=引用隊列時候,實例被它註冊, 或者實例不被註冊,當queue=ReferenceQueue.NULL時候; next=null.
  • Pending: queue = ReferenceQueue with which instance is registered; next = Following instance in queue, or this if at end of list.
    等待:queue=引用隊列時候,實例被它註冊, next=剩下的queue隊列裏面的實例,或者=this,如果this是隊列的最後一個。
  • Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
    in queue, or this if at end of list.
    入隊:queue=ReferenceQueue.ENQUEUED , next=剩下的queue隊列裏面的實例,或者=this,如果this是隊列的最後一個
  • Inactive: queue = ReferenceQueue.NULL; next = this.
    終止:隊列=ReferenceQueue.NULL next=this

    三,成員變量

    private T referent; // 被GC引用的對象
    volatile ReferenceQueue queue; //引用隊列
    Reference next; //下個引用
    transient private Reference discovered; ///被VM引用的瞬態對象
    //GC線程在回收的時候的鎖
    // 對象被用來和GC同步。GC必須獲得鎖在每個回收的生命週期。
    // 更關鍵的是任何持有鎖的代碼儘可能快的執行完,沒有分配新的對象,並避免使用使用者的代碼。
    static private class Lock { }
    private static Lock lock = new Lock();
    // 排隊的引用集合。當處理引用的線程刪除引用時候,收集器添加引用到這個集合。
    這個集合受上面的對象鎖保護。
    private static Reference pending = null;

如何處理pending的

1 : tryHandlePending

static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c;
        try {
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    if (waitForNotify) {
                        lock.wait();
                    }
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            Thread.yield();
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }
        if (c != null) {
            c.clean();
            return true;
        }
        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }
    ```
    pending != null時候,pending賦值給r, discovered賦值給pending,discovered等於null
    如果r.的queue不爲空時候,放入Queue中
static {
    ThreadGroup tg = Thread.currentThread().getThreadGroup();
    for (ThreadGroup tgn = tg;
         tgn != null;
         tg = tgn, tgn = tg.getParent());
    Thread handler = new ReferenceHandler(tg, "Reference Handler");
    /* If there were a special system-only priority greater than
     * MAX_PRIORITY, it would be used here
     */
    handler.setPriority(Thread.MAX_PRIORITY);
    handler.setDaemon(true);
    handler.start();

    // provide access in SharedSecrets
    SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
        @Override
        public boolean tryHandlePendingReference() {
            return tryHandlePending(false);
        }
    });
}

“`
去起來一個守護進程,來搞tryHandlePending
java.lang.ref.Reference
有些問題,自己也不太明白(先這樣記錄下),如果又錯誤,請留言.

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