0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

jemalloc分配機(jī)制的介紹及其優(yōu)化實(shí)踐

Linux閱碼場(chǎng) ? 來(lái)源:字節(jié)跳動(dòng)SYS Tech ? 2023-05-30 09:12 ? 次閱讀

前言

C++ 語(yǔ)言中提供了大量的類(lèi)庫(kù)和編程接口,雖然可以幫助開(kāi)發(fā)者提升研發(fā)效率,但在特定場(chǎng)景下,其性能表現(xiàn)仍存在優(yōu)化空間。開(kāi)發(fā)者往往追求極致的代碼性能邏輯,一點(diǎn)點(diǎn)的優(yōu)化改變就可以幫助業(yè)務(wù)獲得良好的性能收益。在字節(jié)降本提效的過(guò)程中,STE 團(tuán)隊(duì)在算力監(jiān)控系統(tǒng)中發(fā)現(xiàn) Jemalloc 是業(yè)務(wù)的前五大 CPU 熱點(diǎn)基礎(chǔ)庫(kù),具有很高的潛在性能優(yōu)化空間。因此,從 2019 年開(kāi)始對(duì) Jemalloc 進(jìn)行深度優(yōu)化,并在字節(jié)內(nèi)部進(jìn)行了大范圍的優(yōu)化落地,幫助業(yè)務(wù)團(tuán)隊(duì)取得了較好的收益。本文將主要介紹 Jemalloc 的基本原理以及一些簡(jiǎn)單易用的優(yōu)化方法,幫助開(kāi)發(fā)者在 Jemalloc 的實(shí)際應(yīng)用中,獲得更好的性能表現(xiàn)。

內(nèi)存相關(guān)概念簡(jiǎn)介

Linux內(nèi)存分配與分配器

當(dāng)代 Linux 系統(tǒng)中可以同時(shí)運(yùn)行多種多樣的進(jìn)程,并且進(jìn)程之間可以做到內(nèi)存互相隔離,這得益于 Linux 的進(jìn)程地址空間管理。

一個(gè)進(jìn)程的地址空間中,包含了靜態(tài)內(nèi)存、以及動(dòng)態(tài)內(nèi)存(常說(shuō)的堆棧),棧的動(dòng)態(tài)分配和釋放由編譯器完成,對(duì)于堆上內(nèi)存,Linux 提供了 brk、sbrk、mmap、munmap 等系統(tǒng)調(diào)用來(lái)進(jìn)行內(nèi)存分配和釋放,但是這些函數(shù)的直接使用會(huì)帶來(lái)不小的理解門(mén)檻和使用復(fù)雜性,如 brk 需要指定堆的上界地址,容易出現(xiàn)內(nèi)存錯(cuò)誤;mmap 直接申請(qǐng) pagesize 為單位的內(nèi)存,對(duì)于小于此內(nèi)存的分配會(huì)造成極大的內(nèi)存浪費(fèi)。因此需要有內(nèi)存分配器來(lái)輔助管理堆的動(dòng)態(tài)申請(qǐng)和釋放。

通常內(nèi)存分配器如 ptmalloc提供了 malloc 等函數(shù)來(lái)進(jìn)行內(nèi)存的分配,free 進(jìn)行內(nèi)存釋放,這些函數(shù)在底層調(diào)用了 brk、mmap 等函數(shù)申請(qǐng)內(nèi)存,并以地址的形式返回給用戶,用戶在 malloc、free 匹配的情況下不必?fù)?dān)心在分配和釋放時(shí)出現(xiàn)內(nèi)存錯(cuò)誤或者內(nèi)存浪費(fèi)。

內(nèi)存碎片

雖然內(nèi)存分配器在一定程度上保證了內(nèi)存的利用率,但是不可避免地會(huì)出現(xiàn)內(nèi)存碎片,包括了內(nèi)存頁(yè)內(nèi)碎片和內(nèi)存頁(yè)間碎片,碎片的產(chǎn)生會(huì)導(dǎo)致部分內(nèi)存不可用,內(nèi)存碎片的大小也是評(píng)估一個(gè)內(nèi)存分配器好壞的重要指標(biāo)。

常見(jiàn)的內(nèi)存分配管理算法

堆上內(nèi)存以鏈?zhǔn)叫问酱嬖?,最?jiǎn)單的動(dòng)態(tài)內(nèi)存分配算法有:

First fit:尋找找第一個(gè)滿足請(qǐng)求 size 的內(nèi)存塊做分配

Next fit:從當(dāng)前分配的地址開(kāi)始,尋找下一個(gè)滿足請(qǐng)求 size 的空閑塊

best fist:對(duì)空閑塊進(jìn)行排序,然后找第一個(gè)滿足要求的空閑塊

另外還有 Buddy 算法和 Slab 算法,也是 jemalloc 中用到的核心算法:

Buddy allocation

e6e17012-fe80-11ed-90ce-dac502259ad0.png

Buddy 算法簡(jiǎn)單來(lái)說(shuō)如上圖,一般 2 的 n 次冪大小來(lái)管理內(nèi)存,當(dāng)申請(qǐng)的內(nèi)存 size 較小,且當(dāng)前空閑內(nèi)存塊均大于 size 的兩倍,那么會(huì)將較大的塊分裂,直到分裂出大于size,并小于 size * 2的塊為止;當(dāng)內(nèi)存 size 較大時(shí)則相反,會(huì)將空閑塊不斷合并。

Buddy 算法沒(méi)有塊間內(nèi)存碎片,但是塊內(nèi)內(nèi)存碎片較大,可以看到當(dāng)申請(qǐng) 2KB+1B 的 size 時(shí),需要用 4KB 的內(nèi)存塊,內(nèi)存碎片最壞情況可達(dá) 50%。

Slab allocation

調(diào)用 Linux 系統(tǒng)調(diào)用進(jìn)行內(nèi)存的分配和釋放會(huì)讓程序陷入內(nèi)核態(tài),帶來(lái)不小的性能開(kāi)銷(xiāo),slab 算法應(yīng)運(yùn)而生。每個(gè) slab 都是一塊連續(xù)內(nèi)存,并將其劃分成大小相同的 slots,用 bitmap 來(lái)記錄這些 slots 的空閑情況,內(nèi)存分配時(shí),返回一個(gè) bitmap 中記錄的空閑塊,釋放時(shí),將其記錄忙碌即可,而 slab size 和 slot size 是內(nèi)存碎片大小的關(guān)鍵。

Jemalloc簡(jiǎn)介

Jemalloc 是 malloc(3) 的實(shí)現(xiàn),在現(xiàn)代多線程、高并發(fā)的互聯(lián)網(wǎng)應(yīng)用中,有良好的性能表現(xiàn),并提供了優(yōu)秀的內(nèi)存分析功能。

Jemalloc 主要有以下幾個(gè)特點(diǎn):

高效地分配和釋放內(nèi)存,可以有效提升程序的運(yùn)行速度,并且節(jié)省 CPU 資源

盡量少的內(nèi)存碎片,一個(gè)長(zhǎng)穩(wěn)運(yùn)行地程序如果不控制內(nèi)存碎片的產(chǎn)生,那么可以預(yù)見(jiàn)地這個(gè)程序會(huì)在某一時(shí)刻崩潰,限制了程序的運(yùn)行生命周期

支持堆的 profiling,可以有效地用來(lái)分析內(nèi)存問(wèn)題

支持多樣化的參數(shù),可以針對(duì)自身地程序特點(diǎn)來(lái)定制運(yùn)行時(shí) Jemalloc 各個(gè)模塊大小,以獲得最優(yōu)的性能和資源占用比

下文主要介紹了 Jemalloc 的內(nèi)存分配算法、數(shù)據(jù)結(jié)構(gòu),以及一些針對(duì)具體程序的優(yōu)化實(shí)踐和建議。

Jemalloc核心算法與數(shù)據(jù)結(jié)構(gòu)

Jemalloc 整體的算法和數(shù)據(jù)結(jié)構(gòu)基于高效和低內(nèi)存碎片的原則進(jìn)行設(shè)計(jì),主要體現(xiàn)在:

隔離了大 Size 和小 Size 的內(nèi)存分配(區(qū)分默認(rèn)閾值為 3.5 個(gè) Pagesize),可以有效地減少內(nèi)存碎片

在內(nèi)存重用時(shí)默認(rèn)使用低地址,并將內(nèi)存控制在盡量少的內(nèi)存頁(yè)上

制定 size class 和 slab class,以便減少內(nèi)存碎片

嚴(yán)格限制 Jemalloc 自身的元數(shù)據(jù)大小

用一定數(shù)量的 arena 來(lái)管理內(nèi)存的單元,每個(gè) arena 管理相當(dāng)數(shù)量的線程,arena 之間獨(dú)立,盡量減少多線程時(shí)鎖競(jìng)爭(zhēng)

我們來(lái)看下 Jemalloc 是如何來(lái)實(shí)現(xiàn)這些特性的。

Extent

Jemalloc 的內(nèi)存管理結(jié)合了 buddy 算法和 slab 算法。Jemalloc 引入 extent 的概念,extent 是 arena 管理的內(nèi)存對(duì)象,在 large size 的 allocation 中充當(dāng) buddy 算法中的 chunk,small size allocation 中,充當(dāng) slab。

每個(gè) extent 的大小是 Pagesize 的整數(shù)倍,不同 size 的 extent 會(huì)用 buddy 算法來(lái)進(jìn)行拆分和合并,大內(nèi)存的分配會(huì)直接使用一整個(gè)的 extent 來(lái)存儲(chǔ)。小內(nèi)存的分配使用的是 slab 算法,slab size 的計(jì)算規(guī)則為 size 和 pagesize 的最小公倍數(shù),因此每個(gè)extent總是可以存儲(chǔ)整數(shù)倍個(gè)對(duì)應(yīng) size。

extent 本身設(shè)置 bitmap,來(lái)記錄內(nèi)存占用情況,以及自身的各種屬性,同類(lèi)型的 extents 用 paring heap 存儲(chǔ)。

此外,arena 將 extent 分為多種類(lèi)型,有當(dāng)前正在使用未被填滿的extent,有一段時(shí)間未使用的dirty extent,還有長(zhǎng)時(shí)間未使用的muzzy extent,以及開(kāi)啟retained功能后的retained extent,extent分類(lèi)的作用相當(dāng)于多級(jí)緩存,當(dāng)線程內(nèi)存分配壓力較小時(shí),空余的extent會(huì)被緩存,以備壓力增大時(shí)使用,可以避免與操作系統(tǒng)的交互。

Small size align and Slab size

為了減少頁(yè)內(nèi)內(nèi)存碎片,Jemalloc 對(duì) small size 進(jìn)行了對(duì)齊,對(duì)于每一個(gè) size,以二進(jìn)制的視角來(lái)看,將其分為兩個(gè)數(shù):group、mod。group 表示 size 的二進(jìn)制最高位,如果 size 正好為 2 的冪次,則將其分在上一個(gè) group 中;mod 表示最高位的后兩位,有 0、1、2、3 共 4 種可能。這樣構(gòu)成的 align 后的 size 在同一個(gè) group 中步長(zhǎng)(即兩個(gè)相鄰 mod 計(jì)算得到的 size 之間的差值)相同,group 越大,步長(zhǎng)會(huì)呈 2 的倍數(shù)增長(zhǎng)。

如下圖,框中的 4個(gè)是同一個(gè) group 中 4 種 mod 在 align 后的 size,其中 160 表示包含了 129B 到 160B 在對(duì)齊后的大小:

e723f4fa-fe80-11ed-90ce-dac502259ad0.png

計(jì)算出 aligned size 后,就需要計(jì)算 slab size,每個(gè) slab size 為 pagesize 和 aligned size 的最小公倍數(shù),以防止跨 slab 的 size 或者 slab 無(wú)法被填滿的情況出現(xiàn)。以 4K page 為例,128B 的 slab size 即 4K,160B 的 slab size 為 20K。

Tcache and arena

為了減少多線程下鎖的競(jìng)爭(zhēng),Jemalloc 參考 lkmalloc 和 tcmalloc,實(shí)現(xiàn)了一套由多個(gè) arena 獨(dú)立管理內(nèi)存加 thread cache 的機(jī)制,形成 tcache 有空余空間時(shí)不需要加鎖分配,沒(méi)有空余空間時(shí)將鎖控制在線程所屬 arena 管理的幾個(gè)線程之間的模式。

e77ab0d8-fe80-11ed-90ce-dac502259ad0.png

tcache 中每一個(gè) size 對(duì)應(yīng)一個(gè) bin,當(dāng) tcache 需要填充時(shí),在 arena 中發(fā)生的如下圖:

e7b9cf84-fe80-11ed-90ce-dac502259ad0.png

allocation/dallocation in tcache

tcache 以 thread local storage對(duì)象的形式存儲(chǔ),主要服務(wù)于 small size 和一小部分 large size。

當(dāng) tcache 中有空閑時(shí),一次 malloc 的過(guò)程很簡(jiǎn)單:

對(duì) size 做 align 得到 usize

查找 usize 對(duì)應(yīng)的 bin,bin 為 tcache 中針對(duì)不同 size 設(shè)置的 slots

bin 有空閑地址則直接返回,沒(méi)有空閑地址則會(huì)向 arena 請(qǐng)求填充

每個(gè) bin 的結(jié)構(gòu)如下圖,avail 指向 bin 的起始地址,ncached 初始為 bin 的最大值 ncached_max (與 slab size 相關(guān),最小為 20 最大為 200),每次申請(qǐng)內(nèi)存會(huì)返回 ncached 指向的地址并自減1,直到小于限制值。

e7e4af38-fe80-11ed-90ce-dac502259ad0.png

釋放的時(shí)候相反,當(dāng) tcache 不為空,即 ncached 不等于 bin 的 ncached_max 時(shí),ncached 自加1,并且將 free 的地址填入 bin 中。

Tcache fill

上面的 allocation 過(guò)程是 tcache 中有足夠的空閑塊供分配,當(dāng) tcache 中已經(jīng)沒(méi)有空閑塊時(shí),會(huì)向其所屬的 arena 申請(qǐng) fill,此時(shí) arena 中會(huì)加鎖去分級(jí) extent 取空閑塊,并把當(dāng)前使用的 extent 移入full extent。

Tcache flush

當(dāng) dallocate 觸發(fā) tcache 中又沒(méi)有分配任何內(nèi)存,即 ncached_max 等于 ncached_max 時(shí),tcache 會(huì)觸發(fā) flush,flush 會(huì)將 tcache 中一半的內(nèi)存釋放回原 extent,即將 tache 的可用空間壓縮到原來(lái)的一半,這個(gè)過(guò)程中也會(huì)加對(duì)應(yīng) extent 的鎖以保證同步。

Jemalloc優(yōu)化思路

從上一章節(jié)可以看到,jemalloc 對(duì)于內(nèi)存用的是多級(jí)緩存的思路,tcache 的代價(jià)最小,無(wú)須加鎖可以直接返回;其次是 arena 的 bin->extent,鎖的粒度在對(duì)應(yīng)的 bin 上,會(huì)是 bin 對(duì)應(yīng)的 size 在這個(gè) arena 中無(wú)法再做 fill 或 flush;然后是 dirty extent、muzzy extent,這部分是 arena 全局加鎖,會(huì)鎖住其他線程的 fill 或者 purge,那么在多線程下,我們可以用幾個(gè)思路來(lái)優(yōu)化鎖的競(jìng)爭(zhēng)。

arena優(yōu)化

從上一章節(jié)可知,jemalloc 將鎖的范圍都控制在 arena 中,每個(gè) arena 會(huì)管理一系列線程,線程在 arena 中是平均分配的,arena 默認(rèn)數(shù)量是 CPU 個(gè)數(shù) * 4。因此,當(dāng)我們?cè)谝慌_(tái) 8 核的機(jī)器上運(yùn)行 256 個(gè)線程時(shí),意味著每個(gè)arena 需要管理 8 個(gè)線程,這些線程在內(nèi)存任務(wù)繁重時(shí)會(huì)產(chǎn)生嚴(yán)重的鎖競(jìng)爭(zhēng),從而影響性能。此時(shí)可選擇使用 malloc_conf128,增加 arena 數(shù)量到 128 個(gè),每個(gè) arena 只需管理 2 個(gè)線程,線程之間產(chǎn)生鎖競(jìng)爭(zhēng)的概率就會(huì)大大減小。

此外還可以選擇用 mallocx 隔離線程,讓內(nèi)存分配任務(wù)較重的線程獨(dú)占 arena。

Slab size優(yōu)化

Slab size 的大小如上所述,為 usize 大小和 pagesize 的最小公倍數(shù),這一機(jī)制可以保證減少內(nèi)存碎片,但是tcache 的 fill 與 flush 都與 slab size 相關(guān),一個(gè)和業(yè)務(wù)內(nèi)存模型匹配的 slab class 才可以得到最好的性能效果。

下面是一張 jemalloc 和 ptmalloc 的對(duì)比圖,可以看到在 1024 以下的性能 jemalloc 都優(yōu)于 ptmalloc,但是jemalloc 自身的性能明顯存在波動(dòng),幾個(gè)波動(dòng)出現(xiàn)在 128B、256B、512B 以及 1024B 周?chē)驗(yàn)檫@些 size 本身就是 pagesize 的因子或者公因子較多,所以 slab size 占用的 page 數(shù)也相對(duì)較少,fill 和 flush 所需要的slab數(shù)也越多。

e8297f6e-fe80-11ed-90ce-dac502259ad0.png

dirty decay & muzzy decay

盡管我們希望將所有的 malloc、free 內(nèi)存都可以放在 tcache 中或者 bin 中,這樣可以最大化執(zhí)行效率,但是實(shí)際的程序中這很難做到,因?yàn)槊總€(gè)線程都需要增加內(nèi)存,會(huì)造成不小的內(nèi)存壓力,而且內(nèi)存的申請(qǐng)釋放往往會(huì)有波峰,dirty extents 和 muzzy extents 就可以來(lái)應(yīng)對(duì)這些內(nèi)存申請(qǐng)的波峰,而避免需要轉(zhuǎn)入內(nèi)核態(tài)來(lái)重新申請(qǐng)內(nèi)存頁(yè)。

dirty_decay_ms 和 muzzy_decay_ms 是 jemalloc 中用來(lái)控制長(zhǎng)時(shí)間空閑內(nèi)存衰變的時(shí)間參數(shù),適當(dāng)?shù)財(cái)U(kuò)大 dirty decay 的時(shí)間可以有效地解決性能劣化的尖刺。

Tcache ncached_max

tcache 中每一個(gè) bin 的 slots 數(shù)量由 ncached_max 決定,當(dāng) tcache 中 ncached_max 耗盡時(shí)會(huì)觸發(fā) arena 的 fill tcache 而產(chǎn)生鎖,而 ncached_max 的大小默認(rèn)為 2 * slab size,最小為 20,最大為 200,適當(dāng)?shù)財(cái)U(kuò)大 ncached_max 值可以在一些線程上形成更優(yōu)的 allocation/deallocation 循環(huán)(5.3版本已支持用malloc_conf進(jìn)行更改)。

優(yōu)化方法:調(diào)優(yōu)三板斧

結(jié)合以上優(yōu)化思路,通過(guò)以下步驟對(duì)應(yīng)用進(jìn)行調(diào)優(yōu):

Dump stats

在 long exist 的程序中可調(diào)用 jemalloc 的 malloc_stats_print 函數(shù),dump 出應(yīng)用當(dāng)前內(nèi)存分配信息

// reference: https://jemalloc.net/jemalloc.3.html
void malloc_stats_print(void (*write_cb)(void *, const char *), // 回調(diào)函數(shù),可以寫(xiě)入文件
                        void *cbopaque, // 回調(diào)函數(shù)參數(shù)
                        const char *opts); // stats的一些選項(xiàng),如"J"是導(dǎo)出json格式

或通過(guò)設(shè)置 malloc_conf,在程序運(yùn)行結(jié)束后自動(dòng) dump stats:

export MALLOC_CONF=stats_print:true
stats 分析

用 Json 格式 dump stats 后,可以得到如下圖所示結(jié)構(gòu)的 json 文件:

e8abb29a-fe80-11ed-90ce-dac502259ad0.png

各字段含義可參考:
https://jemalloc.net/jemalloc.3.html

按上一章節(jié)思路,可主要關(guān)注以下幾點(diǎn): (1)arena 數(shù)量與 threads 數(shù)量比例

arena 數(shù):jemalloc->arenas->narenas

threads 數(shù):jemalloc->stats.arenas->merged->nthreads

分析:

threads : arenas 比例代表了單個(gè) arena 中管理的線程數(shù),將 malloc、free 較多,并且有可能產(chǎn)生競(jìng)爭(zhēng)的線程盡量獨(dú)占 arena。

(2)各個(gè) extent 中 mutex 開(kāi)銷(xiāo)

jemalloc->stats.arenas->merged->mutexes

分析

該節(jié)點(diǎn)中的 mutex 操作次數(shù)、等鎖時(shí)間可以反映出該類(lèi)型 extent 的鎖競(jìng)爭(zhēng)程度,若 extent_retained 鎖競(jìng)爭(zhēng)嚴(yán)重,可適當(dāng)調(diào)大 muzzy_decay_ms;同理,當(dāng) extents_muzzy 鎖競(jìng)爭(zhēng)嚴(yán)重,可適當(dāng)調(diào)大 diry_decay_ms;extents_dirty 鎖競(jìng)爭(zhēng)嚴(yán)重,可適當(dāng)調(diào)大 ncached_max,讓malloc 盡量可以在 tcache 中完成

(3)arena 中各個(gè) bin 的 malloc、free 次數(shù)

jemalloc->stats.arenas->merged->bins

分析

bin 中的 nfills 可以反映該 slab 填充的次數(shù),針對(duì) regions 本身較少,nfill 次數(shù)又多的 size,如 521B、1024B、2048B、4096B 等,可適當(dāng)調(diào)大 slab size 來(lái)減小開(kāi)銷(xiāo)

添加MALLOC_CONF參數(shù)或修改代碼

MALLOC_CONF 是 jemalloc 中用來(lái)動(dòng)態(tài)設(shè)置參數(shù)的途徑,無(wú)須重新編譯二進(jìn)制,可以通過(guò) MALLOC_CONF 環(huán)境變量或者 /etc/malloc_conf 軟鏈接形式設(shè)置,參數(shù)之間用 ',' 分割。除需要使用線程獨(dú)占的 arena 外,以上其他優(yōu)化均可通過(guò) MALLOC_CONF 配置來(lái)完成。

(1)arena優(yōu)化方法

narenas 設(shè)置:

export MALLOC_CONF=narenas:xxx  # xxx最大為1024

ln -s "narenas:xxx" /etc/malloc_conf

設(shè)置線程獨(dú)占的 arena:

unsigned thread_set_je_exclusive_arena() {
  unsigned arena_old, arena_new;
  size_t sz = sizeof(unsigned);


  /* Bind to a manual arena. */
  if (mallctl("arenas.create", &arena_new, &sz, NULL, 0)) {
    std::cout << "Jemalloc arena create error
";
    return 0;
  }
  if (mallctl("thread.arena", &arena_old, &sz, &arena_new, sizeof(arena_new))) {
    std::cout << "Thread bind to jemalloc arena error
";
    return 0;
  }
  return arena_new;
}

(2)各類(lèi)大小優(yōu)化方法

dirty extents:

export MALLOC_CONF=dirty_decay_ms:xxx  # -1為不釋放dirty extents,易發(fā)生OOM

muzzy extents:

export MALLOC_CONF=muzzy_decay_ms:xxx  # -1為不釋放muzzy extents,易發(fā)生OOM

tcache ncached_max 調(diào)整,ncached_max 與 slab size 相關(guān),計(jì)算方式為

(slab_size / region_size) << lg_tcache_nslots_mul (默認(rèn)值1)
最大限值為 tcache_nslots_small_max(默認(rèn)200),最小限值為 tcache_nslots_small_min(默認(rèn)20)。

如調(diào)整 32B 的 ncached_max,當(dāng)前系統(tǒng) page size 為 4K,計(jì)算默認(rèn)的 ncached_max 的方法:

(slab_size / region_size) << lg_tcache_nslots_mul = (4096 / 32) << 1 = 256
超過(guò)了 tcache_nslots_small_max,所以 32B 的 ncache_max 默認(rèn)即為 200。

調(diào)整 ncached_max 默認(rèn)值相關(guān)參數(shù):

export 
MALLOC_CONF=tcache_nslots_small_min:xxx,tcache_nslots_small_max:xxx,lg_tcache_nslots_mul:xxx

Slab size 設(shè)置方法:

export MALLOC_CONF="slab_sizes17|100-200:1|128-128:2" # -左右表示size范圍,:后設(shè)置page數(shù),|分割各個(gè)不同的size范圍

字節(jié)業(yè)務(wù)優(yōu)化案例

Jemalloc 的 stats dump 已經(jīng)集成到監(jiān)控系統(tǒng)中,經(jīng)過(guò)分析發(fā)現(xiàn),字節(jié)內(nèi)部的應(yīng)用普遍線程數(shù)量較多,在 arena 中的鎖競(jìng)爭(zhēng)比較激烈,并且 allocte/deallocte 集中在某些線程中,因此可以通過(guò)讓核心線程獨(dú)占 arena 來(lái)完成優(yōu)化。以其中一個(gè)業(yè)務(wù)在平臺(tái)上的 stats 數(shù)據(jù)為例:

e8dabafe-fe80-11ed-90ce-dac502259ad0.png

可以看到進(jìn)程總線程數(shù)為 1776 個(gè),arenas 數(shù)量為 256 個(gè),平均每個(gè) arena 中的內(nèi)存需要有 7-8 個(gè)線程共享,再查看 mutexs 的 stats :

e9271fa2-fe80-11ed-90ce-dac502259ad0.png

可以看到在 extents 中產(chǎn)生鎖的開(kāi)銷(xiāo)并不小,首先選擇擴(kuò)大 arenas 的數(shù)量,從 256 擴(kuò)大到 1024 個(gè),發(fā)現(xiàn) CPU 相對(duì)下降了 4.5%,但是相對(duì)的內(nèi)存上漲了 10%,在分析代碼后,發(fā)現(xiàn) allocate/deallocate 較多的線程總數(shù)量只有80+,針對(duì)這些線程通過(guò) mallctl 單獨(dú)創(chuàng)建了 arena,并綁定 tcache,并調(diào)小其他線程的 muzzy_decay_ms,最終為該業(yè)務(wù)節(jié)省了 4% 的 CPU 收益,內(nèi)存基本持平。

總結(jié)

最好的基礎(chǔ)庫(kù)總是通用的,最適合的基礎(chǔ)庫(kù)總是最個(gè)性化的。對(duì)于 jemalloc 在業(yè)務(wù)上的優(yōu)化與實(shí)踐,STE團(tuán)隊(duì)進(jìn)行不斷探索,采集內(nèi)存信息并進(jìn)行平臺(tái)化展示,以便業(yè)務(wù)及時(shí)發(fā)現(xiàn)自身程序在 jemalloc 上的性能瓶頸,并做出針對(duì)性地調(diào)優(yōu),目前已在 10+ 業(yè)務(wù)上進(jìn)行參數(shù)優(yōu)化平均幫助各業(yè)務(wù)團(tuán)隊(duì)節(jié)省了 3% 的 CPU(jemalloc 在部分業(yè)務(wù)中平均占用 10% ~ 15% 的CPU)。未來(lái) STE 團(tuán)隊(duì)將繼續(xù)深入 jemalloc 性能優(yōu)化,探索定制化的業(yè)務(wù)內(nèi)存分配和管理方案,以獲得更好的優(yōu)化成果。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10702

    瀏覽量

    209411
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    587

    瀏覽量

    27182
  • 分配器
    +關(guān)注

    關(guān)注

    0

    文章

    192

    瀏覽量

    25612
  • JSON
    +關(guān)注

    關(guān)注

    0

    文章

    113

    瀏覽量

    6899
  • malloc
    +關(guān)注

    關(guān)注

    0

    文章

    52

    瀏覽量

    55
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    cc2530網(wǎng)絡(luò)地址分配機(jī)制是什么樣的?

    是2.5.1a,不知道這個(gè)版本所采用的網(wǎng)絡(luò)地址分配機(jī)制是什么樣的?這個(gè)版本還閱讀協(xié)議棧解壓出來(lái)的document有沒(méi)有用,會(huì)不會(huì)已經(jīng)過(guò)時(shí)了,那些document基本上都是zstack2007的謝謝大家了。
    發(fā)表于 04-01 10:19

    綜合布線主分配機(jī)房(MDF)是什么

    摘要:綜合布線主分配機(jī)房(MDF)是建筑物的進(jìn)出線配線架及語(yǔ)音、數(shù)據(jù)、圖像、控制等設(shè)備及線纜端接的匯集地。是對(duì)建筑物或者建筑群的布線以及布線應(yīng)用系統(tǒng)進(jìn)行管理、維護(hù)的最主要設(shè)備場(chǎng)所。根據(jù)國(guó)內(nèi)相關(guān)標(biāo)準(zhǔn)
    發(fā)表于 09-09 08:44

    在ARM64 CentOS系統(tǒng)下MySQL使用jemalloc內(nèi)存占用問(wèn)題的分析過(guò)程和解決方法

    1、Jemalloc 簡(jiǎn)介Jemalloc是由Jason Evans在FreeBSD項(xiàng)目中引入的內(nèi)存分配管理器,它的優(yōu)勢(shì)在于減少內(nèi)存碎片和提升高并發(fā)場(chǎng)景下內(nèi)存的分配效率。
    發(fā)表于 05-09 10:34

    Linux內(nèi)存管理中的Slab分配機(jī)制

    早期Linux 的內(nèi)存分配機(jī)制采用伙伴算法, 當(dāng)請(qǐng)求分配的內(nèi)存大小為幾十個(gè)字節(jié)或幾百個(gè)字節(jié)時(shí)會(huì)產(chǎn)生內(nèi)存碎片, 嚴(yán)重消耗系統(tǒng)資源。現(xiàn)今采用Slab 機(jī)制可以緩存物理空間的申請(qǐng)和回
    發(fā)表于 04-24 10:49 ?11次下載

    WCDMA中的鑒權(quán)和密鑰分配機(jī)制

    為了滿足第三代移動(dòng)通信安全體系的要求, 詳細(xì)討論了WCDMA 系統(tǒng)中的鑒權(quán)和密鑰分配機(jī)制,從應(yīng)用的角度分析了具體的算法和參數(shù), 如從HEöA uC 發(fā)送鑒權(quán)消息到VLRöSGSN 的過(guò)程,VLR&o
    發(fā)表于 06-02 16:29 ?35次下載

    高效的Snort規(guī)則匹配機(jī)制

    該文在分析了 Snort 的規(guī)則及其檢測(cè)過(guò)程的基礎(chǔ)之上,提出一種動(dòng)態(tài)規(guī)則匹配機(jī)制,增加選項(xiàng)索引鏈表,對(duì)規(guī)則匹配的次序進(jìn)行動(dòng)態(tài)調(diào)整,從而提高規(guī)則匹配的速度。關(guān)鍵詞:Snort
    發(fā)表于 06-13 14:09 ?23次下載

    Snort匹配機(jī)制的改進(jìn)

    基于規(guī)則的模式匹配是Snort 檢測(cè)引擎的主要機(jī)制,本文在結(jié)合協(xié)議分析和模式匹配的基礎(chǔ)上,對(duì)Snort 匹配機(jī)制進(jìn)行了改進(jìn)。首先對(duì)從網(wǎng)絡(luò)中獲取的數(shù)據(jù)包進(jìn)行預(yù)先處理,利用協(xié)議分
    發(fā)表于 12-18 17:35 ?14次下載

    用戶可靠性的眾包系統(tǒng)任務(wù)分配機(jī)制

    針對(duì)現(xiàn)有研究對(duì)眾包系統(tǒng)中用戶可靠性考慮不足的問(wèn)題,假設(shè)每個(gè)用戶針對(duì)不同類(lèi)型任務(wù)具有不同的可靠性,并在此基礎(chǔ)上設(shè)計(jì)了一種基于用戶可靠性的眾包系統(tǒng)任務(wù)分配機(jī)制。首先,以任務(wù)發(fā)布者的收益最大化為優(yōu)化目標(biāo)
    發(fā)表于 11-27 18:01 ?6次下載

    基于IPv6的DiffServ流標(biāo)簽分配機(jī)制

    本文在DiffServ模型的基礎(chǔ)上,改變了路由器的功能,使用IPv6流標(biāo)簽字段和源地址作為關(guān)鍵字,在路由器中建立轉(zhuǎn)發(fā)表,根據(jù)關(guān)鍵字轉(zhuǎn)發(fā)IPv6分組,提高轉(zhuǎn)發(fā)速度;同時(shí),在DS區(qū)域使用一種流標(biāo)簽分配機(jī)制,避免了流標(biāo)簽的重復(fù)和混亂。
    發(fā)表于 12-12 19:05 ?0次下載
    基于IPv6的DiffServ流標(biāo)簽<b class='flag-5'>分配機(jī)制</b>

    基于分簇的資源分配機(jī)制

    針對(duì)Macro-Femto網(wǎng)絡(luò)中Femtocell與Macrocell之間的干擾問(wèn)題,提出了一種基于分簇的資源分配機(jī)制。該機(jī)制結(jié)合圖論及凸優(yōu)化理論對(duì)毫微微節(jié)點(diǎn)分簇;隨后采用基于速率公平的子信道
    發(fā)表于 01-26 17:58 ?0次下載
    基于分簇的資源<b class='flag-5'>分配機(jī)制</b>

    比特幣分配機(jī)制最公平的原因是什么

    比特幣協(xié)議中最早設(shè)計(jì)的分配機(jī)制至今仍然是最公平、也是最可靠的。
    發(fā)表于 07-19 14:59 ?2050次閱讀

    一種基于信任的物聯(lián)網(wǎng)頻譜資源分配機(jī)制

    隨著無(wú)線網(wǎng)絡(luò)的快速發(fā)展,物聯(lián)網(wǎng)中頻譜資源的高效分配問(wèn)題亟需解決,為此,提出一種基于信任的頻譜資源分配機(jī)制TSRA。借鑒拍賣(mài)理論建立頻譜資源拍賣(mài)系統(tǒng)模型,根據(jù)信任理論確定用戶間的信任關(guān)系以縮小客戶網(wǎng)絡(luò)
    發(fā)表于 04-27 14:23 ?6次下載
    一種基于信任的物聯(lián)網(wǎng)頻譜資源<b class='flag-5'>分配機(jī)制</b>

    基于拓?fù)浣Y(jié)構(gòu)與分配機(jī)制的PoW共識(shí)機(jī)制

    對(duì)經(jīng)典的PoW共識(shí)機(jī)制進(jìn)行改進(jìn),改變了礦工所挖出區(qū)塊接入主鏈的條件和收益分配策略,從而提出了一種改進(jìn)共識(shí)機(jī)制。與PoW不同,在該改進(jìn)共識(shí)機(jī)制中,首個(gè)生成的由N個(gè)子區(qū)塊相連的子鏈將被整體
    發(fā)表于 05-31 15:48 ?3次下載

    基于權(quán)值和基于夏普利值的圖像酬勞分配機(jī)制

    基于權(quán)值和基于夏普利值的圖像酬勞分配機(jī)制
    發(fā)表于 06-24 15:35 ?43次下載

    Linux內(nèi)核中的頁(yè)面分配機(jī)制

    Linux內(nèi)核中是如何分配出頁(yè)面的,如果我們站在CPU的角度去看這個(gè)問(wèn)題,CPU能分配出來(lái)的頁(yè)面是以物理頁(yè)面為單位的。也就是我們計(jì)算機(jī)中常講的分頁(yè)機(jī)制。本文就看下Linux內(nèi)核是如何管理,釋放和
    的頭像 發(fā)表于 08-07 15:51 ?146次閱讀
    Linux內(nèi)核中的頁(yè)面<b class='flag-5'>分配機(jī)制</b>