您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)怎么分析Curve中的內(nèi)存管理,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
Curve 實(shí)踐過程中遇到過幾次內(nèi)存相關(guān)的問題,與操作系統(tǒng)內(nèi)存管理相關(guān)的是以下兩次:
chunkserver
上內(nèi)存無法釋放
mds
出現(xiàn)內(nèi)存緩慢增長的現(xiàn)象
內(nèi)存問題在開發(fā)階段大多很難發(fā)現(xiàn),測試階段大壓力穩(wěn)定性測試(持續(xù)跑7*24小時(shí)以上)、異常測試往往比較容易出問題,當(dāng)然這還需要我們在測試階段足夠仔細(xì),除了關(guān)注io相關(guān)指標(biāo)外,還要關(guān)注服務(wù)端內(nèi)存/CPU/網(wǎng)卡等資源使用情況以及采集的metric
是否符合預(yù)期。比如上述問題mds 內(nèi)存緩慢增長
,如果只關(guān)注io是否正常,在測試階段是無法發(fā)現(xiàn)的。內(nèi)存問題出現(xiàn)后定位也不容易,尤其在軟件規(guī)模較大的情況下。
下面主要是從開發(fā)者的角度來談 Curve 中的內(nèi)存管理,不會(huì)過度強(qiáng)調(diào)內(nèi)存管理理論,目的是把我們在軟件開發(fā)過程中對 Linux 內(nèi)存管理的認(rèn)知、內(nèi)存問題分析的一些方法分享給大家。本文會(huì)從以下幾個(gè)方面展開:
內(nèi)存布局。結(jié)合 Curve 軟件說明內(nèi)存布局。
內(nèi)存分配策略。說明內(nèi)存分配器的必要性,以及需要解決的問題和具有的特點(diǎn),然后通過舉例說明其中一個(gè)內(nèi)存分配器的內(nèi)存管理方法。
Curve 的內(nèi)存管理。介紹當(dāng)前 Curve 軟件內(nèi)存分配器的選擇及原因。
在說內(nèi)存管理之前,首先簡要介紹下內(nèi)存布局相關(guān)知識。
軟件在運(yùn)行時(shí)需要占用一定量的內(nèi)存用來存放一些數(shù)據(jù),但進(jìn)程并不直接與存放數(shù)據(jù)的物理內(nèi)存打交道,而是直接操作虛擬內(nèi)存。物理內(nèi)存是真實(shí)的存在,就是內(nèi)存條;虛擬內(nèi)存為進(jìn)程隱藏了物理內(nèi)存這一概念,為進(jìn)程提供了簡潔易用的接口和更加復(fù)雜的功能。本文說的內(nèi)存管理是指虛擬內(nèi)存管理。為什么需要抽象一層虛擬內(nèi)存?虛擬內(nèi)存和物理內(nèi)存是如何映射管理的?物理尋址是怎么的?這些虛擬內(nèi)存更下層的問題不在本文討論范圍。
Linux 為每個(gè)進(jìn)程維護(hù)了一個(gè)單獨(dú)的虛擬地址空間,包括兩個(gè)部分進(jìn)程虛擬存儲器(用戶空間)和內(nèi)核虛擬存儲器(內(nèi)核空間),小編主要討論進(jìn)程可操作的用戶空間,形式如下圖。
現(xiàn)在我們使用pmap
查看運(yùn)行中的 curve-mds 虛擬空間的分布。pmap
用于查看進(jìn)程的內(nèi)存映像信息,該命令讀取的是/proc/[pid]/maps
中的信息。
// pmap -X {進(jìn)程id} 查看進(jìn)程內(nèi)存分布 sudo pmap -X 2804620 // pmap 獲取的 curve-mds 內(nèi)存分布有很多項(xiàng) Address Perm Offset Device Inode Size Rss Pss Referenced Anonymous ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping // 為了方便展示這里把從 Pss 后面的數(shù)值刪除了, 中間部分地址做了省略 2804620: /usr/bin/curve-mds -confPath=/etc/curve/mds.conf -mdsAddr=127.0.0.1:6666 -log_dir=/data/log/curve/mds -graceful_quit_on_sigterm=true -stderrthreshold=3 Address Perm Offset Device Inode Size Rss Pss Mapping c000000000 rw-p 00000000 00:00 0 65536 1852 1852 559f0e2b9000 r-xp 00000000 41:42 37763836 9112 6296 6296 curve-mds 559f0eb9f000 r--p 008e5000 41:42 37763836 136 136 136 curve-mds 559f0ebc1000 rw-p 00907000 41:42 37763836 4 4 4 curve-mds 559f0ebc2000 rw-p 00000000 00:00 0 10040 4244 4244 559f1110a000 rw-p 00000000 00:00 0 2912 2596 2596 [heap] 7f6124000000 rw-p 00000000 00:00 0 156 156 156 7f6124027000 ---p 00000000 00:00 0 65380 0 0 7f612b7ff000 ---p 00000000 00:00 0 4 0 0 7f612b800000 rw-p 00000000 00:00 0 8192 8 8 7f612c000000 rw-p 00000000 00:00 0 132 4 4 7f612c021000 ---p 00000000 00:00 0 65404 0 0 ..... 7f6188cff000 ---p 0026c000 41:42 37750237 2044 0 0 7f61895b7000 r-xp 00000000 41:42 50201214 96 96 0 libpthread-2.24.so 7f61895cf000 ---p 00018000 41:42 50201214 2044 0 0 libpthread-2.24.so 7f61897ce000 r--p 00017000 41:42 50201214 4 4 4 libpthread-2.24.so 7f61897cf000 rw-p 00018000 41:42 50201214 4 4 4 libpthread-2.24.so 7f61897d0000 rw-p 00000000 00:00 0 16 4 4 7f61897d4000 r-xp 00000000 41:42 50200647 16 16 0 libuuid.so.1.3.0 7f61897d8000 ---p 00004000 41:42 50200647 2044 0 0 libuuid.so.1.3.0 7f61899d7000 r--p 00003000 41:42 50200647 4 4 4 libuuid.so.1.3.0 7f61899d8000 rw-p 00004000 41:42 50200647 4 4 4 libuuid.so.1.3.0 7f61899d9000 r-xp 00000000 41:42 37617895 9672 8904 8904 libetcdclient.so 7f618a34b000 ---p 00972000 41:42 37617895 2048 0 0 libetcdclient.so 7f618a54b000 r--p 00972000 41:42 37617895 6556 5664 5664 libetcdclient.so 7f618abb2000 rw-p 00fd9000 41:42 37617895 292 252 252 libetcdclient.so 7f618abfb000 rw-p 00000000 00:00 0 140 60 60 7f618ac1e000 r-xp 00000000 41:42 50201195 140 136 0 ld-2.24.so 7f618ac4a000 rw-p 00000000 00:00 0 1964 1236 1236 7f618ae41000 r--p 00023000 41:42 50201195 4 4 4 ld-2.24.so 7f618ae42000 rw-p 00024000 41:42 50201195 4 4 4 ld-2.24.so 7f618ae43000 rw-p 00000000 00:00 0 4 4 4 7fffffd19000 rw-p 00000000 00:00 0 132 24 24 [stack] 7fffffdec000 r--p 00000000 00:00 0 8 0 0 [vvar] 7fffffdee000 r-xp 00000000 00:00 0 8 4 0 [vdso] ffffffffff600000 r-xp 00000000 00:00 0 4 0 0 [vsyscall] ======= ===== ===== 1709344 42800 37113
上面輸出中進(jìn)程實(shí)際占用的空間是從 0x559f0e2b9000 開始,不是內(nèi)存分布圖上畫的 0x40000000。這是因?yàn)榈刂房臻g分布隨機(jī)化(ASLR),它的作用是隨機(jī)生成進(jìn)程地址空間(例如棧、庫或者堆)的關(guān)鍵部分的起始地址,目的是增強(qiáng)系統(tǒng)安全性、避免惡意程序?qū)σ阎刂饭?。Linux 中/proc/sys/kernel/randomize_va_space
的值為 1 或 2 表示地址空間隨機(jī)化已開啟,數(shù)值1、2的區(qū)別在于隨機(jī)化的關(guān)鍵部分不同;0表示關(guān)閉。
接下來 0x559f0e2b9000 0x559f0eb9f000 0x559f0ebc1000 三個(gè)地址起始對應(yīng)的文件都是curve-mds ,但是對該文件的擁有不同的權(quán)限,各字母代表的權(quán)限r-讀 w-寫 x-可執(zhí)行 p-私有 s-共享
。curve-mds 是elf
類型文件,從內(nèi)容的角度看,它包含代碼段、數(shù)據(jù)段、BSS段等;從裝載到內(nèi)存角度看,操作系統(tǒng)不關(guān)心各段所包含的內(nèi)容,只關(guān)心跟裝載相關(guān)的問題,主要是權(quán)限,所以操作系統(tǒng)會(huì)把相同權(quán)限的段合并在一起去加載,就是我們這里看到的以代碼段為代表的權(quán)限為可讀可執(zhí)行的段、以只讀數(shù)據(jù)為代表的權(quán)限為只讀的段、以數(shù)據(jù)段和 BSS 段為代表的權(quán)限為可讀可寫的段。
再往下 0x559f1110a000 開始,對應(yīng)上圖的運(yùn)行時(shí)堆,運(yùn)行時(shí)動(dòng)態(tài)分配的內(nèi)存會(huì)在這上面進(jìn)行 。我們發(fā)現(xiàn)也是在.bss
段的結(jié)束位置進(jìn)行了隨機(jī)偏移。
接著 0x7f6124000000 開始,對應(yīng)的是上圖 mmap 內(nèi)存映射區(qū)域,這一區(qū)域包含動(dòng)態(tài)庫、用戶申請的大片內(nèi)存等。到這里我們可以看到Heap
和Memory Mapping Region
都可以用于程序中使用malloc
動(dòng)態(tài)分配的內(nèi)存,在下一節(jié)內(nèi)存分配策略中會(huì)有展開,也是本文關(guān)注重點(diǎn)。
接著 0x7fffffd19000 開始是??臻g,一般有數(shù)兆字節(jié)。
最后 vvar、vdso、vsyscall 區(qū)域是為了實(shí)現(xiàn)虛擬函數(shù)調(diào)用以加速部分系統(tǒng)調(diào)用,使得程序可以不進(jìn)入內(nèi)核態(tài)1直接調(diào)用系統(tǒng)調(diào)用。這里不具體展開。
我們平時(shí)使用malloc
分配出來的內(nèi)存是在Heap
和Memory Mapping Region
這兩個(gè)區(qū)域。mallloc 實(shí)際上由兩個(gè)系統(tǒng)調(diào)用完成:brk
和mmap
brk 分配的區(qū)域?qū)?yīng)堆 heap
mmap 分配的區(qū)域?qū)?yīng) Memory Mapping Region
如果讓每個(gè)開發(fā)者在軟件開發(fā)時(shí)都直接使用系統(tǒng)調(diào) brk 和 mmap 用去分配釋放內(nèi)存,那開發(fā)效率將會(huì)變得很低,而且也很容易出錯(cuò)。一般來說我們在開發(fā)中都會(huì)直接使用內(nèi)存管理庫,當(dāng)前主流的內(nèi)存管理器有三種:ptmalloc``tcmalloc``jemalloc
, 都提供malloc, free
接口,glibc 默認(rèn)使用ptmalloc。這些庫的作用是管理它通過系統(tǒng)調(diào)用獲得的內(nèi)存區(qū)域,一般來說一個(gè)優(yōu)秀的通用內(nèi)存分配器應(yīng)該具有以下特征:
額外的空間損耗量盡量少。比如應(yīng)用程序只需要5k內(nèi)存,結(jié)果分配器給他分配了10k,會(huì)造成空間的浪費(fèi)。
分配的速度盡可能快。
盡量避免內(nèi)存碎片。下面我們結(jié)合圖來直觀的感受下內(nèi)存碎片。
通用性、兼容性、可移植性、易調(diào)試。
我們通過下面一幅圖直觀說明下 glibc 默認(rèn)的內(nèi)存管理器 ptmalloc 在單線程情況下堆內(nèi)存的回收和分配:
malloc(30k)
通過系統(tǒng)調(diào)用 brk 擴(kuò)展堆頂?shù)姆绞椒峙鋬?nèi)存。
malloc(20k)
通過系統(tǒng)調(diào)用 brk 繼續(xù)擴(kuò)展堆頂。
malloc(200k)
默認(rèn)情況下請求內(nèi)存大于 128K (由M_MMAP_THRESHOLD
確定,默認(rèn)大小為128K,可以調(diào)整),就利用系統(tǒng)調(diào)用 mmap分配內(nèi)存。
free(30k)
這部分空間并沒有歸還給系統(tǒng),而是 ptmalloc 管理著。由1、2兩步的 malloc 可以看出,我們分配空間的時(shí)候調(diào)用 brk 進(jìn)行堆頂擴(kuò)展,那歸還空間給系統(tǒng)是相反操作即收縮堆頂。這里由于第二步 malloc(20k) 的空間并未釋放,所以此時(shí)堆頂無法收縮。這部分空間是可以被再分配的,比如此時(shí) malloc(10k),那可以從這里分配 10k 空間,而不需要通過 brk 去申請。考慮這樣一種情況,堆頂?shù)目臻g一直被占用,堆頂向下的空間有部分被應(yīng)用程序釋放但由于空間不夠沒有再被使用,就會(huì)形成內(nèi)存碎片
。
free(20k)
這部分空間應(yīng)用程序釋放后,ptmalloc 會(huì)把剛才的 20k 和 30k 的區(qū)域合并,如果堆頂空閑超過M_TRIM_THREASHOLD
,會(huì)把這塊區(qū)域收縮歸還給操作系統(tǒng)。
free(200k)
mmap分配出來的空間會(huì)直接歸還給系統(tǒng)。
那對于多線程程序,ptmalloc 又是怎么區(qū)分配的?多線程情況下需要處理各線程間的競爭,如果還是按照之前的方式,小于HEAP_MAX_SIZE
( 64 位系統(tǒng)默認(rèn)大小為 64M )的空間使用 brk 擴(kuò)展堆頂, 大于HEAP_MAX_SIZE
的空間使用 mmap 申請,那對于線程數(shù)量較多的程序,如果每個(gè)線程上存在比較頻繁的內(nèi)存分配操作,競爭會(huì)很激烈。ptmalloc 的方法是使用多個(gè)分配區(qū)域,包含兩種類型分配區(qū):主分配區(qū) 和 動(dòng)態(tài)分配區(qū)。
主分配區(qū):會(huì)在Heap
和Memory Mapping Region
這兩個(gè)區(qū)域分配內(nèi)存
動(dòng)態(tài)分配區(qū):在Memory Mapping Region
區(qū)域分配內(nèi)存,在 64 位系統(tǒng)中默認(rèn)每次申請的大小位。Main 線程和先執(zhí)行 malloc 的線程使用不同的動(dòng)態(tài)分配區(qū),動(dòng)態(tài)分配區(qū)的數(shù)量一旦增加就不會(huì)減少了。動(dòng)態(tài)分配區(qū)的數(shù)量對于 32 位系統(tǒng)最多是 ( 2 number of cores + 1 ) 個(gè),對于 64 位系統(tǒng)最多是( 8 number of cores + 1 )個(gè)。
舉個(gè)多線程的例子來看下這種情況下的空間分配:
// 共有三個(gè)線程 // 主線程:分配一次 4k 空間 // 線程1: 分配 100 次 4k 空間 // 線程2: 分配 100 次 4k 空間 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sys/types.h> void* threadFunc(void* id) { std::vector<char *> malloclist; for (int i = 0; i < 100; i++) { malloclist.emplace_back((char*) malloc(1024 * 4)); } sleep(300); // 這里等待是為查看內(nèi)存分布 } int main() { pthread_t t1,t2; int id1 = 1; int id2 = 2; void* s; int ret; char* addr; addr = (char*) malloc(4 * 1024); pthread_create(&t1, NULL, threadFunc, (void *) &id1); pthread_create(&t2, NULL, threadFunc, (void *) &id2); pthread_join(t1, NULL); pthread_join(t2, NULL); return 0; }
我們用 pmap 查看下該程序的內(nèi)存分布情況:
741545: ./memory_test Address Perm Offset Device Inode Size Rss Pss Mapping 56127705a000 r-xp 00000000 08:02 62259273 4 4 4 memory_test 56127725a000 r--p 00000000 08:02 62259273 4 4 4 memory_test 56127725b000 rw-p 00001000 08:02 62259273 4 4 4 memory_test 5612784b9000 rw-p 00000000 00:00 0 132 8 8 [heap] **7f0df0000000 rw-p 00000000 00:00 0 404 404 404 7f0df0065000 ---p 00000000 00:00 0 65132 0 0 7f0df8000000 rw-p 00000000 00:00 0 404 404 404 7f0df8065000 ---p 00000000 00:00 0 65132 0 0** 7f0dff467000 ---p 00000000 00:00 0 4 0 0 7f0dff468000 rw-p 00000000 00:00 0 8192 8 8 7f0dffc68000 ---p 00000000 00:00 0 4 0 0 7f0dffc69000 rw-p 00000000 00:00 0 8192 8 8 7f0e00469000 r-xp 00000000 08:02 50856517 1620 1052 9 libc-2.24.so 7f0e005fe000 ---p 00195000 08:02 50856517 2048 0 0 libc-2.24.so 7f0e007fe000 r--p 00195000 08:02 50856517 16 16 16 libc-2.24.so 7f0e00802000 rw-p 00199000 08:02 50856517 8 8 8 libc-2.24.so 7f0e00804000 rw-p 00000000 00:00 0 16 12 12 7f0e00808000 r-xp 00000000 08:02 50856539 96 96 1 libpthread-2.24.so 7f0e00820000 ---p 00018000 08:02 50856539 2044 0 0 libpthread-2.24.so 7f0e00a1f000 r--p 00017000 08:02 50856539 4 4 4 libpthread-2.24.so 7f0e00a20000 rw-p 00018000 08:02 50856539 4 4 4 libpthread-2.24.so 7f0e00a21000 rw-p 00000000 00:00 0 16 4 4 7f0e00a25000 r-xp 00000000 08:02 50856513 140 140 1 ld-2.24.so 7f0e00c31000 rw-p 00000000 00:00 0 16 16 16 7f0e00c48000 r--p 00023000 08:02 50856513 4 4 4 ld-2.24.so 7f0e00c49000 rw-p 00024000 08:02 50856513 4 4 4 ld-2.24.so 7f0e00c4a000 rw-p 00000000 00:00 0 4 4 4 7ffe340be000 rw-p 00000000 00:00 0 132 12 12 [stack] 7ffe3415c000 r--p 00000000 00:00 0 8 0 0 [vvar] 7ffe3415e000 r-xp 00000000 00:00 0 8 4 0 [vdso] ffffffffff600000 r-xp 00000000 00:00 0 4 0 0 [vsyscall] ====== ==== === 153800 2224 943
關(guān)注上面加粗的部分,紅色區(qū)域加起來是 65536K,其中有 404K 是 rw-p (可讀可寫)權(quán)限,65132K 是 —-p (不可讀寫)權(quán)限;黃色區(qū)域類似。兩個(gè)線程分配的時(shí) ptmalloc 分別給了 動(dòng)態(tài)分區(qū),并且每次申請 64M 內(nèi)存,再從這 64M 中切分出一部分給應(yīng)用程序。
這里還有一個(gè)有意思的現(xiàn)象:我們用strace -f -e "brk, mmap, munmap" -p {pid}
去跟蹤程序查看下 malloc 中的系統(tǒng)調(diào)用:
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f624a169000 strace: Process 774601 attached [pid 774018] mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f6249968000 [pid 774601] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f6241968000 [pid 774601] munmap(0x7f6241968000, 40468480strace: Process 774602 attached ) = 0 [pid 774601] munmap(0x7f6248000000, 26640384) = 0 [pid 774602] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f623c000000 [pid 774602] munmap(0x7f6240000000, 67108864) = 0
這里主線程 [774018] 要求分配了 8M+4k 空間;線程1 [774601] 先 mmap 了 128M 空間,再分歸還了 0x7f6241968000 為起始地址的 40468480 字節(jié) 和 0x7f6248000000為起始地址的 26640384 字節(jié),那剩余的部分是 0x7F6244000000 ~ 0x7F6248000000。先申請?jiān)贇w還是為了讓分配的這部分內(nèi)存的起止地址是字節(jié)對齊的。
Curve 中選擇了兩種分配器:ptmalloc
和jemalloc
。其中 MDS 使用默認(rèn)的 ptmalloc,Chunkserver 和 Client 端使用 jemalloc。
本文開頭提到的兩個(gè)問題在這里進(jìn)行說明。首先是MDS內(nèi)存緩慢增長,現(xiàn)象是每天增長 3G。這個(gè)問題分析的過程如下:
首先是使用pmap
查看內(nèi)存分布。我們用 pmap 查看內(nèi)存緩慢增長的 curve-mds 內(nèi)存分配情況,發(fā)現(xiàn)在 Memory Mapping Region 存在著大量分配的 64M 內(nèi)存,且觀察一段時(shí)間后都不釋放還在一直分配。從這里懷疑存在內(nèi)存泄露。
然后查看應(yīng)用上請求的壓力情況。查看MDS 上相關(guān)的業(yè)務(wù) metric,發(fā)現(xiàn) MDS 上的壓力都很小,一些控制面 rpc 的 iops 在幾百左右,不應(yīng)該是業(yè)務(wù)壓力較大導(dǎo)致的。
接下來查看 curve-mds 部分 64M 內(nèi)存上的數(shù)據(jù)。使用gdb -p {pid} attach
跟蹤線程,dump meemory mem.bin {addr1} {addr2}
獲取指定地址段的內(nèi)存,然后查看這部分內(nèi)存內(nèi)容,基本確定幾個(gè)懷疑點(diǎn)。
根據(jù)這幾個(gè)點(diǎn)去排查代碼,看是否有內(nèi)存泄露。
Chunkserver 端不是開始就使用 jemalloc 的,最初也是用的默認(rèn)的 ptmalloc。換成 jemalloc 是本文開始提到的 Chunkserver 在測試過程中出現(xiàn)內(nèi)存無法釋放的問題,這個(gè)問題的現(xiàn)象是:chunkserver的內(nèi)存在 2 個(gè) 小時(shí)內(nèi)增長很快,一共增長了 50G 左右,但后面并未釋放。這個(gè)問題分析的過程如下:
首先分析內(nèi)存中數(shù)據(jù)來源。這一點(diǎn)跟 MDS 不同,MDS 上都是控制面的請求以及一些元數(shù)據(jù)的緩存。而Chunkserver 上的內(nèi)存增長一般來自兩個(gè)地方:一是用戶發(fā)送的請求,二是 copyset 的 leader 和 follower 之間同步數(shù)據(jù)。這兩個(gè)都會(huì)涉及到 brpc 模塊。
brpc 的內(nèi)存管理有兩個(gè)模塊 IOBuf 和 ResourcePool。IOBuf 中的空間一般用于存放用戶數(shù)據(jù),ResourcePool 管理 socket、bthread_id 等對象,管理的內(nèi)存對象單位是 64K 。
查看對應(yīng)模塊的一些趨勢指標(biāo)。觀察這兩個(gè)模塊的metric,發(fā)現(xiàn) IOBuf 和 ResourcePool 這段時(shí)間內(nèi)占用的內(nèi)存都有相同的增長趨勢。
IOBuf 后面將占用的內(nèi)存歸還給 ptmalloc, ResourcePool 中管理的內(nèi)存不會(huì)歸還給 ptmalloc 而是自己管理。
從這個(gè)現(xiàn)象我們懷疑 IOBuf 歸還給 ptmalloc 的內(nèi)存 ptmalloc 無法釋放。
分析驗(yàn)證。結(jié)合第二節(jié)的內(nèi)存分配策略,如果堆頂?shù)目臻g一直被占用,那堆頂向下的空間也是無法被釋放的。仍然可以使用 pmap 查看當(dāng)前堆上內(nèi)存的大小以及內(nèi)存的權(quán)限(是否有很多 —-p 權(quán)限的內(nèi)存)來確定猜想。因此后面 Chunkserver 使用了 jemalloc。這里可以看到在多線程情況下,如果一部分內(nèi)存被應(yīng)用長期持有,使用 ptmalloc 也許就會(huì)遇到內(nèi)存無法釋放的問題。
以上就是怎么分析Curve中的內(nèi)存管理,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。