最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty分布式ByteBuf使用的回收邏輯剖析

 更新時間:2022年03月28日 17:32:48   作者:向南是個萬人迷  
這篇文章主要介紹了Netty分布式ByteBuf使用的回收邏輯剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前文傳送門:ByteBuf使用subPage級別內(nèi)存分配

ByteBuf回收

之前的章節(jié)我們提到過, 堆外內(nèi)存是不受jvm垃圾回收機制控制的, 所以我們分配一塊堆外內(nèi)存進行ByteBuf操作時, 使用完畢要對對象進行回收, 這一小節(jié), 就以PooledUnsafeDirectByteBuf為例講解有關(guān)內(nèi)存分配的相關(guān)邏輯

PooledUnsafeDirectByteBuf中內(nèi)存釋放的入口方法是其父類AbstractReferenceCountedByteBuf中的release方法:

@Override
 public boolean release() {
     return release0(1);
 }

這里調(diào)用了release0, 跟進去

private boolean release0(int decrement) {
    for (;;) {
        int refCnt = this.refCnt;
        if (refCnt < decrement) {
            throw new IllegalReferenceCountException(refCnt, -decrement);
        }
        if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) { 
            if (refCnt == decrement) { 
                deallocate();
                return true;
            }
            return false;
        }
    }
}

 if (refCnt == decrement) 中判斷當前byteBuf是否沒有被引用了, 如果沒有被引用, 則通過deallocate()方法進行釋放

因為我們是以PooledUnsafeDirectByteBuf為例, 所以這里會調(diào)用其父類PooledByteBuf的deallocate方法:

protected final void deallocate() {
    if (handle >= 0) {
        final long handle = this.handle;
        this.handle = -1;
        memory = null;
        chunk.arena.free(chunk, handle, maxLength, cache);
        recycle();
    }
}

this.handle = -1表示當前的ByteBuf不再指向任何一塊內(nèi)存

memory = null這里將memory也設(shè)置為null

chunk.arena.free(chunk, handle, maxLength, cache)這一步是將ByteBuf的內(nèi)存進行釋放

recycle()是將對象放入的對象回收站, 循環(huán)利用

我們首先分析free方法

void free(PoolChunk<T> chunk, long handle, int normCapacity, PoolThreadCache cache) {
    //是否為unpooled
    if (chunk.unpooled) {
        int size = chunk.chunkSize();
        destroyChunk(chunk);
        activeBytesHuge.add(-size);
        deallocationsHuge.increment();
    } else {
        //那種級別的Size
        SizeClass sizeClass = sizeClass(normCapacity);
        //加到緩存里
        if (cache != null && cache.add(this, chunk, handle, normCapacity, sizeClass)) {
            return;
        }
        //將緩存對象標記為未使用
        freeChunk(chunk, handle, sizeClass);
    }
}

首先判斷是不是unpooled, 我們這里是Pooled, 所以會走到else塊中:

sizeClass(normCapacity)計算是哪種級別的size, 我們按照tiny級別進行分析

cache.add(this, chunk, handle, normCapacity, sizeClass)是將當前當前ByteBuf進行緩存

我們之前講過, 再分配ByteBuf時首先在緩存上分配, 而這步, 就是將其緩存的過程, 跟進去:

boolean add(PoolArena<?> area, PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass) {
    //拿到MemoryRegionCache節(jié)點
    MemoryRegionCache<?> cache = cache(area, normCapacity, sizeClass);
    if (cache == null) {
        return false;
    }
    //將chunk, 和handle封裝成實體加到queue里面
    return cache.add(chunk, handle);
}

首先根據(jù)根據(jù)類型拿到相關(guān)類型緩存節(jié)點, 這里會根據(jù)不同的內(nèi)存規(guī)格去找不同的對象, 我們簡單回顧一下, 每個緩存對象都包含一個queue, queue中每個節(jié)點是entry, 每一個entry中包含一個chunk和handle, 可以指向唯一的連續(xù)的內(nèi)存

我們跟到cache中

private MemoryRegionCache<?> cache(PoolArena<?> area, int normCapacity, SizeClass sizeClass) {
    switch (sizeClass) {
    case Normal:
        return cacheForNormal(area, normCapacity);
    case Small:
        return cacheForSmall(area, normCapacity);
    case Tiny:
        return cacheForTiny(area, normCapacity);
    default:
        throw new Error();
    }
}

假設(shè)我們是tiny類型, 這里就會走到cacheForTiny(area, normCapacity)方法中, 跟進去:

private MemoryRegionCache<?> cacheForTiny(PoolArena<?> area, int normCapacity) { 
    int idx = PoolArena.tinyIdx(normCapacity);
    if (area.isDirect()) {
        return cache(tinySubPageDirectCaches, idx);
    }
    return cache(tinySubPageHeapCaches, idx);
}

這個方法我們之前剖析過, 就是根據(jù)大小找到第幾個緩存中的第幾個緩存, 拿到下標之后, 通過cache去超相對應(yīng)的緩存對象:  

private static <T>  MemoryRegionCache<T> cache(MemoryRegionCache<T>[] cache, int idx) {
    if (cache == null || idx > cache.length - 1) {
        return null;
    }
    return cache[idx];
}

我們這里看到, 是直接通過下標拿的緩存對象

回到add方法中

boolean add(PoolArena<?> area, PoolChunk chunk, long handle, int normCapacity, SizeClass sizeClass) {
    //拿到MemoryRegionCache節(jié)點
    MemoryRegionCache<?> cache = cache(area, normCapacity, sizeClass);
    if (cache == null) {
        return false;
    }
    //將chunk, 和handle封裝成實體加到queue里面
    return cache.add(chunk, handle);
}

這里的cache對象調(diào)用了一個add方法, 這個方法就是將chunk和handle封裝成一個entry加到queue里面

我們跟到add方法中:

public final boolean add(PoolChunk<T> chunk, long handle) {
    Entry<T> entry = newEntry(chunk, handle); 
    boolean queued = queue.offer(entry);
    if (!queued) {
        entry.recycle();
    }
    return queued;
}

我們之前介紹過, 從在緩存中分配的時候從queue彈出一個entry, 會放到一個對象池里面, 而這里Entry<T> entry = newEntry(chunk, handle)就是從對象池里去取一個entry對象, 然后將chunk和handle進行賦值

然后通過queue.offer(entry)加到queue中

我們回到free方法中

void free(PoolChunk<T> chunk, long handle, int normCapacity, PoolThreadCache cache) {
    //是否為unpooled
    if (chunk.unpooled) {
        int size = chunk.chunkSize();
        destroyChunk(chunk);
        activeBytesHuge.add(-size);
        deallocationsHuge.increment();
    } else {
        //那種級別的Size
        SizeClass sizeClass = sizeClass(normCapacity);
        //加到緩存里
        if (cache != null && cache.add(this, chunk, handle, normCapacity, sizeClass)) {
            return;
        } 
        freeChunk(chunk, handle, sizeClass);
    }
}

這里加到緩存之后, 如果成功, 就會return, 如果不成功, 就會調(diào)用freeChunk(chunk, handle, sizeClass)方法, 這個方法的意義是, 將原先給ByteBuf分配的內(nèi)存區(qū)段標記為未使用

跟進freeChunk簡單分析下:

void freeChunk(PoolChunk<T> chunk, long handle, SizeClass sizeClass) {
    final boolean destroyChunk;
    synchronized (this) {
        switch (sizeClass) {
        case Normal:
            ++deallocationsNormal;
            break;
        case Small:
            ++deallocationsSmall;
            break;
        case Tiny:
            ++deallocationsTiny;
            break;
        default:
            throw new Error();
        }
        destroyChunk = !chunk.parent.free(chunk, handle);
    }
    if (destroyChunk) {
        destroyChunk(chunk);
    }
}

我們再跟到free方法中:

boolean free(PoolChunk<T> chunk, long handle) {
    chunk.free(handle);
    if (chunk.usage() < minUsage) {
        remove(chunk);
        return move0(chunk);
    }
    return true;
}

chunk.free(handle)的意思是通過chunk釋放一段連續(xù)的內(nèi)存

再跟到free方法中:

void free(long handle) {
    int memoryMapIdx = memoryMapIdx(handle);
    int bitmapIdx = bitmapIdx(handle);

    if (bitmapIdx != 0) { 
        PoolSubpage<T> subpage = subpages[subpageIdx(memoryMapIdx)];
        assert subpage != null && subpage.doNotDestroy;
        PoolSubpage<T> head = arena.findSubpagePoolHead(subpage.elemSize);
        synchronized (head) {
            if (subpage.free(head, bitmapIdx & 0x3FFFFFFF)) {
                return;
            }
        }
    }
    freeBytes += runLength(memoryMapIdx);
    setValue(memoryMapIdx, depth(memoryMapIdx));
    updateParentsFree(memoryMapIdx);
}

 if (bitmapIdx != 0)這 里判斷是當前緩沖區(qū)分配的級別是Page還是Subpage, 如果是Subpage, 則會找到相關(guān)的Subpage將其位圖標記為0

如果不是subpage, 這里通過分配內(nèi)存的反向標記, 將該內(nèi)存標記為未使用

這段邏輯可以讀者自行分析, 如果之前分配相關(guān)的知識掌握扎實的話, 這里的邏輯也不是很難

回到PooledByteBuf的deallocate方法中:

protected final void deallocate() {
    if (handle >= 0) {
        final long handle = this.handle;
        this.handle = -1;
        memory = null;
        chunk.arena.free(chunk, handle, maxLength, cache);
        recycle();
    }
}

最后, 通過recycle()將釋放的ByteBuf放入對象回收站, 有關(guān)對象回收站的知識, 會在以后的章節(jié)進行剖析

以上就是內(nèi)存回收的大概邏輯,更多關(guān)于Netty分布式ByteBuf使用回收的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • swagger配置正式環(huán)境中不可訪問的問題

    swagger配置正式環(huán)境中不可訪問的問題

    這篇文章主要介紹了swagger配置正式環(huán)境中不可訪問的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java中Druid連接池連接超時獲取不到連接的解決

    Java中Druid連接池連接超時獲取不到連接的解決

    這篇文章主要介紹了Java中Druid連接池連接超時獲取不到連接的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • java 服務(wù)器接口快速開發(fā)之servlet詳細教程

    java 服務(wù)器接口快速開發(fā)之servlet詳細教程

    Servlet(Server Applet)是Java Servlet的簡稱,稱為小服務(wù)程序或服務(wù)連接器,用Java編寫的服務(wù)器端程序,具有獨立于平臺和協(xié)議的特性,主要功能在于交互式地瀏覽和生成數(shù)據(jù),生成動態(tài)Web內(nèi)容
    2021-06-06
  • 如何在Java中優(yōu)雅地使用正則表達式詳解

    如何在Java中優(yōu)雅地使用正則表達式詳解

    這篇文章主要給大家介紹了關(guān)于如何在Java中優(yōu)雅地使用正則表達式的相關(guān)資料,正則表達式就是一個字符串,但和普通的字符串不同的是,正則表達式是對一組相似字符串的抽象,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-02-02
  • 創(chuàng)建Jersey REST 服務(wù),基于Maven的實現(xiàn)

    創(chuàng)建Jersey REST 服務(wù),基于Maven的實現(xiàn)

    下面小編就為大家?guī)硪黄獎?chuàng)建Jersey REST 服務(wù),基于Maven的實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java終止線程實例和stop()方法源碼閱讀

    Java終止線程實例和stop()方法源碼閱讀

    這篇文章主要介紹了Java終止線程實例和stop()方法源碼閱讀,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12
  • mybatis?plus框架@TableField注解不生效問題及解決方案

    mybatis?plus框架@TableField注解不生效問題及解決方案

    最近遇到一個mybatis plus的問題,@TableField注解不生效,導(dǎo)致查出來的字段反序列化后為空,今天通過本文給大家介紹下mybatis?plus框架的@TableField注解不生效問題總結(jié),需要的朋友可以參考下
    2022-03-03
  • Java Servlet3.0異步處理問題

    Java Servlet3.0異步處理問題

    這篇文章主要介紹了Java中Servlet3.0異步處理的原理以及遇到的問題分析,需要的朋友參考一下。
    2017-12-12
  • 一文帶你入門SpringMVC的配置與使用

    一文帶你入門SpringMVC的配置與使用

    Spring MVC是Spring Framework的一部分,是基于Java實現(xiàn)MVC的輕量級Web框架。本文將通過一些簡單示例帶大家掌握SpringMVC的配置與使用,感興趣的可以了解一下
    2022-11-11
  • Java面試突擊之Bean作用域詳解

    Java面試突擊之Bean作用域詳解

    Spring?框架作為一個管理?Bean?的?IoC?容器,那么?Bean?自然是?Spring?中的重要資源了,那?Bean?的作用域是什么意思?又有幾種類型呢?接下來我們一起來看
    2022-08-08

最新評論

伊宁县| 铜陵市| 清水县| 云梦县| 五常市| 海口市| 莱西市| 于田县| 英山县| 来凤县| 宜良县| 微博| 边坝县| 玉田县| 榆中县| 承德县| 嘉峪关市| 福安市| 鸡东县| 凤冈县| 司法| 交城县| 衢州市| 赫章县| 铜川市| 阿巴嘎旗| 建阳市| 光泽县| 高安市| 黎平县| 泰安市| 义马市| 上饶市| 盖州市| 报价| 津南区| 班玛县| 抚顺市| 邢台市| 揭东县| 辽阳县|