Netty源碼分析----PoolChunkList

(*文章基于Netty4.1.22版本)

整體介紹

在Netty的內(nèi)存分配的整體架構(gòu)中,按我的理解,PoolChunkList是為了解決隨著分配的次數(shù)增加儡循,分配一段連續(xù)內(nèi)存失敗率提高的問(wèn)題隔披。
試想一下在Chunk中我們分配了很多小的內(nèi)存枢冤,16B鸠姨,32B,把整個(gè)Chunk都切割成這種小的內(nèi)存塊淹真,那么當(dāng)我們想要分配8KB或者更大的內(nèi)存的時(shí)候讶迁,就會(huì)失敗,因?yàn)槠渌鸆hunk被切割成很小的內(nèi)存碎片核蘸,無(wú)法分配很大的一段內(nèi)存巍糯,所以PoolChunkList的結(jié)構(gòu)就出現(xiàn)了,將不同使用率的PoolChunk分隔開客扎,增加了分配大的連續(xù)段成功的幾率祟峦。
PoolChunkList是一個(gè)鏈表,結(jié)構(gòu)如下:


PoolChunkList結(jié)構(gòu).png

在整個(gè)PoolArena中徙鱼,共有6個(gè)PoolChunkList宅楞,使用率越大的在鏈表的后面,按照不同的使用率疆偿,命名如下:

  1. qInit:使用率 0 ~ 25
  2. q000:使用率 1 ~ 50
  3. q025:使用率 25 ~ 75
  4. q050:使用率 50 ~ 100
  5. q075:使用率 75 ~ 100
  6. q100:使用率 100 ~ 100

源碼分析

變量介紹

    private final PoolArena<T> arena;//該 Chunk所屬的Arena
    private final PoolChunkList<T> nextList;// 下一個(gè)使用率的ChunkList
    private final int minUsage;// 最小使用率
    private final int maxUsage;// 最小使用率
    private final int maxCapacity;// 最大的容量
    private PoolChunk<T> head;// ChunkList中的頭節(jié)點(diǎn)

初始化

    PoolChunkList(PoolArena<T> arena, PoolChunkList<T> nextList, int minUsage, int maxUsage, int chunkSize) {
        assert minUsage <= maxUsage;
        this.arena = arena;
        this.nextList = nextList;
        this.minUsage = minUsage;
        this.maxUsage = maxUsage;
        maxCapacity = calculateMaxCapacity(minUsage, chunkSize);
    }

簡(jiǎn)單的賦值操作咱筛,重點(diǎn)看下calculateMaxCapacity方法

    private static int calculateMaxCapacity(int minUsage, int chunkSize) {
        minUsage = minUsage0(minUsage);//max(1, minUsage)

        if (minUsage == 100) {// 如果最小使用率都百分百了,自然最大可用空間為0
            return 0;
        }
        return  (int) (chunkSize * (100L - minUsage) / 100L);
    }

分配

    boolean allocate(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
        // 如果當(dāng)前ChunkList有Chunk可以分配 或者 請(qǐng)求的大小符合ChunkList的范圍
        if (head == null || normCapacity > maxCapacity) {
            return false;
        }

        // 遍歷ChunkList中的Chunk進(jìn)行分配
        for (PoolChunk<T> cur = head;;) {
            long handle = cur.allocate(normCapacity);
            if (handle < 0) {// 分配失敗杆故,找下一個(gè)
                cur = cur.next;
                if (cur == null) {
                    return false;
                }
            } else {
                cur.initBuf(buf, handle, reqCapacity);// 初始化buf,將buf和Chunk關(guān)聯(lián)
                if (cur.usage() >= maxUsage) {// 分配好之后溉愁,如果大于當(dāng)前ChunkList处铛,那么移動(dòng)到下一個(gè)ChunkList
                    remove(cur);
                    nextList.add(cur);
                }
                return true;
            }
        }
    }

添加Chunk

當(dāng)一個(gè)Chunk要進(jìn)入ChunkList,要調(diào)用add方法

    void add(PoolChunk<T> chunk) {
        // 如果說(shuō)加入的這個(gè)chunk的使用率大于當(dāng)前ChunkList最大的使用率拐揭,那么肯定不能加入當(dāng)前的ChunkList
        // 要加入下一個(gè)ChunkList中撤蟆,直到找到合適的ChunkList
        if (chunk.usage() >= maxUsage) {
            nextList.add(chunk);
            return;
        }
        add0(chunk);
    }
    // 設(shè)置Chunk所屬的ChunkList,并加入到head前面堂污,并將該Chunk設(shè)置為新的head
    void add0(PoolChunk<T> chunk) {
        chunk.parent = this;
        if (head == null) {
            head = chunk;
            chunk.prev = null;
            chunk.next = null;
        } else {
            chunk.prev = null;
            chunk.next = head;
            head.prev = chunk;
            head = chunk;
        }
    }

釋放Chunk

當(dāng)從Chunk分配的內(nèi)存使用完后家肯,在調(diào)用Chunk的free方法釋放內(nèi)存之后,這個(gè)Chunk的使用率會(huì)發(fā)生變化盟猖,可能需要移動(dòng)該Chunk

    boolean free(PoolChunk<T> chunk, long handle) {
        chunk.free(handle);
        // //如果釋放之后讨衣,使用率低于該ChunkList的最低使用率,則從該ChunkList中移除式镐,添加到前面的ChunkList
        if (chunk.usage() < minUsage) {
            remove(chunk);
            // 在鏈表上尋找使用率相符的ChunkList添加
            return move0(chunk);
        }
        return true;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末反镇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子娘汞,更是在濱河造成了極大的恐慌歹茶,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異惊豺,居然都是意外死亡燎孟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門尸昧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缤弦,“玉大人,你說(shuō)我怎么就攤上這事彻磁“澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵衷蜓,是天一觀的道長(zhǎng)累提。 經(jīng)常有香客問(wèn)我,道長(zhǎng)磁浇,這世上最難降的妖魔是什么斋陪? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮置吓,結(jié)果婚禮上无虚,老公的妹妹穿的比我還像新娘。我一直安慰自己衍锚,他們只是感情好友题,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著戴质,像睡著了一般度宦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上告匠,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天戈抄,我揣著相機(jī)與錄音,去河邊找鬼后专。 笑死划鸽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的戚哎。 我是一名探鬼主播裸诽,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼建瘫!你這毒婦竟也來(lái)了崭捍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤啰脚,失蹤者是張志新(化名)和其女友劉穎殷蛇,沒(méi)想到半個(gè)月后实夹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粒梦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年亮航,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匀们。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缴淋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泄朴,到底是詐尸還是另有隱情重抖,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布祖灰,位于F島的核電站钟沛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏局扶。R本人自食惡果不足惜恨统,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望三妈。 院中可真熱鬧畜埋,春花似錦、人聲如沸畴蒲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饿凛。三九已至狞玛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涧窒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工锭亏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纠吴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓慧瘤,卻偏偏與公主長(zhǎng)得像戴已,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锅减,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容