netty對象池使用與回收

來源:互聯網
上載者:User

標籤:link   oid   存在   elements   override   ast   儲存   state   span   

1. Recycler對象池  Recycler抽象類別的實現非常簡單,只有三個方法:  擷取對象:Recycler:get()  回收對象:Recycler:recycle()  建立對象:Recycler:newObject()  newObject為抽象方法,需要由實作類別自己實現此方法來建立對象。  Recycler對象池目的是儘可能的重複利用同一線程建立的對象,同時為了避免佔用過多的記憶體,回收對象時採用一定的比例回收對象(預設1/7規則 注釋中有解釋),未回收的對象由jvm記憶體回收機制來處理。  Recycler對象池的資料存放區結構如下:  

  和建立stack相同的線程回收對象時儲存在elements數組(pushNow方法回收),如果不是同一個線程則放入WeakOrderQueue隊列中,等到需要get對象時且stack為空白,會將WeakOrderQueue集合的所有元素根據一定的規則轉移到stack的elements數組中。

2. 對象的擷取

  首先判斷池中是否存在對象,如果由則優先從本地線程stack中擷取Object,如果stack為空白時,再將其他線程queue集合的所有對象根據一定的規則轉移到本地線程stack中(1/7規則),然後再從stack擷取Object並返回.
  如果池中不存在對象,建立對象並返回。   相關代碼如下:   
    public final T get() {        if (maxCapacityPerThread == 0) {            return newObject((Handle<T>) NOOP_HANDLE);        }        Stack<T> stack = threadLocal.get();        DefaultHandle<T> handle = stack.pop();//首先判斷池中是否存在對象,如果由則優先從本地線程stack中擷取Object,如果stack為空白時,再將其他線程queue集合的所有對象根據一定的規則轉移到本地線程stack中(1/7規則),然後再從stack擷取Object並返回.        if (handle == null) {//如果池中不存在對象,建立對象並返回。            handle = stack.newHandle();            handle.value = newObject(handle);        }        //        System.out.println(threadLocal.getClass() + "=" + stack + "=" + handle);        return (T) handle.value;    }    DefaultHandle<T> pop() {        int size = this.size;        if (size == 0) {首先判斷池中是否存在對象//            if (!scavenge()) {//如果stack為空白時,再將其他線程queue集合的所有對象根據一定的規則轉移到本地線程stack中(1/7規則)                return null;            }            size = this.size;        }        size--;        DefaultHandle ret = elements[size];        elements[size] = null;        if (ret.lastRecycledId != ret.recycleId) {            throw new IllegalStateException("recycled multiple times");        }        ret.recycleId = 0;        ret.lastRecycledId = 0;        this.size = size;        return ret;    }        boolean scavenge() {        // continue an existing scavenge, if any        if (scavengeSome()) {            return true;        }        // reset our scavenge cursor        prev = null;        cursor = head;        return false;    }    boolean scavengeSome() {        WeakOrderQueue prev;        WeakOrderQueue cursor = this.cursor;        if (cursor == null) {            prev = null;            cursor = head;            if (cursor == null) {                return false;            }        } else {            prev = this.prev;        }        boolean success = false;        do {            if (cursor.transfer(this)) {//將其他線程queue集合的所有對象根據一定的規則轉移到本地線程stack中(1/7規則)                success = true;                break;            }            WeakOrderQueue next = cursor.next;            if (cursor.owner.get() == null) {                // If the thread associated with the queue is gone, unlink it, after                // performing a volatile read to confirm there is no data left to collect.                // We never unlink the first queue, as we don‘t want to synchronize on updating the head.                if (cursor.hasFinalData()) {                    for (;;) {                        if (cursor.transfer(this)) {                            success = true;                        } else {                            break;                        }                    }                }                if (prev != null) {                    prev.setNext(next);                }            } else {                prev = cursor;            }            cursor = next;        } while (cursor != null && !success);//遍曆所有的WeakOrderQueue        this.prev = prev;        this.cursor = cursor;        return success;    }    boolean transfer(Stack<?> dst) {        Link head = this.head.link;        if (head == null) {            return false;        }        if (head.readIndex == LINK_CAPACITY) {            if (head.next == null) {                return false;            }            this.head.link = head = head.next;        }        final int srcStart = head.readIndex;        int srcEnd = head.get();        final int srcSize = srcEnd - srcStart;        if (srcSize == 0) {            return false;        }        final int dstSize = dst.size;        final int expectedCapacity = dstSize + srcSize;        if (expectedCapacity > dst.elements.length) {            final int actualCapacity = dst.increaseCapacity(expectedCapacity);            srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd);        }        if (srcStart != srcEnd) {            final DefaultHandle[] srcElems = head.elements;            final DefaultHandle[] dstElems = dst.elements;            int newDstSize = dstSize;            for (int i = srcStart; i < srcEnd; i++) {//將queue中所有元素按照(1/7規則)儲存到stack中                DefaultHandle element = srcElems[i];                if (element.recycleId == 0) {                    element.recycleId = element.lastRecycledId;                } else if (element.recycleId != element.lastRecycledId) {                    throw new IllegalStateException("recycled already");                }                srcElems[i] = null;                if (dst.dropHandle(element)) {                    // Drop the object.                    continue;                }                element.stack = dst;                dstElems[newDstSize++] = element;            }            if (srcEnd == LINK_CAPACITY && head.next != null) {                // Add capacity back as the Link is GCed.                this.head.reclaimSpace(LINK_CAPACITY);                this.head.link = head.next;            }            head.readIndex = srcEnd;            if (dst.size == newDstSize) {                return false;            }            dst.size = newDstSize;            return true;        } else {            // The destination stack is full already.            return false;        }    }        
View Code

3.  回收對象

  如果當前回收的線程是原始線程(建立對象的線程),那麼調用pushNow,如果超過Stack的容量(預設4*1024)或者1/7規則 就drop(由jvm回收釋放)
  如果當前回收的線程不是原始線程,那麼調用pushLater,如果當前線程是第一次回收原始線程的對象,需要由當前線程建立的WeakOrderQueue(原始線程的stack對象中可以關聯其他線程的WeakOrderQueue)。如果建立隊列成功,則進入該隊列;失敗(queue個數大於maxDelayedQueues)則放棄該對象(由jvm回收釋放)注釋:1)由本地線程的WeakOrderQueue回收對象,這麼做的原因時避免並發(races競爭),而且不是每個對象都有對象回收池來回收,如果超過最大容量限制會放棄,而且本地線程stack採用1/8規則措施,而且將異地線程queue的對象轉移到本地線程stack時也採取1/8規則措施   2)1/7規則是指每7個對象只留取1個回收,剩餘部分放棄,如1-7個回收1個,8-15回收2個......
回收對象的相關代碼如下:
     (1)DefaultHandle類        @Override        public void recycle(Object object) {            if (object != value) {                throw new IllegalArgumentException("object does not belong to handle");            }            stack.push(this);        }            (2)Stack類        void push(DefaultHandle<?> item) {        Thread currentThread = Thread.currentThread();        if (threadRef.get() == currentThread) {            // The current Thread is the thread that belongs to the Stack, we can try to push the object now.            pushNow(item);        } else {            // The current Thread is not the one that belongs to the Stack            // (or the Thread that belonged to the Stack was collected already), we need to signal that the push            // happens later.            pushLater(item, currentThread);        }           (3)private void pushNow(DefaultHandle<?> item) {            if ((item.recycleId | item.lastRecycledId) != 0) {                throw new IllegalStateException("recycled already");            }            item.recycleId = item.lastRecycledId = OWN_THREAD_ID;            int size = this.size;            if (size >= maxCapacity || dropHandle(item)) {//為了避免回收對象數量太多,佔用太多記憶體,採取了1/8規則措施,參數可調                // Hit the maximum capacity or should drop - drop the possibly youngest object.                return;            }            if (size == elements.length) {                elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));            }            elements[size] = item;            this.size = size + 1;        }                (4)private void pushLater(DefaultHandle<?> item, Thread thread) {            // we don‘t want to have a ref to the queue as the value in our weak map            // so we null it out; to ensure there are no races with restoring it later            // we impose a memory ordering here (no-op on x86)            Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();            WeakOrderQueue queue = delayedRecycled.get(this);            if (queue == null) {                if (delayedRecycled.size() >= maxDelayedQueues) {回收池的異地隊列個數有限制,每個隊列的容量也有限制                    // Add a dummy queue so we know we should drop the object                    delayedRecycled.put(this, WeakOrderQueue.DUMMY);                    return;                }                // Check if we already reached the maximum number of delayed queues and if we can allocate at all.                if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {                    // drop object                    return;                }                delayedRecycled.put(this, queue);            } else if (queue == WeakOrderQueue.DUMMY) {                // drop object                return;            }            queue.add(item);        }        (5)WeakOrderQueue類        void add(DefaultHandle<?> handle) {            handle.lastRecycledId = id;            Link tail = this.tail;            int writeIndex;            if ((writeIndex = tail.get()) == LINK_CAPACITY) {                if (!head.reserveSpace(LINK_CAPACITY)) {                    // Drop it.                    return;                }                // We allocate a Link so reserve the space                this.tail = tail = tail.next = new Link();                writeIndex = tail.get();            }            tail.elements[writeIndex] = handle;            handle.stack = null;            // we lazy set to ensure that setting stack to null appears before we unnull it in the owning thread;            // this also means we guarantee visibility of an element in the queue if we see the index updated            tail.lazySet(writeIndex + 1);        } 
View Code

 

netty對象池使用與回收

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.