溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么分析Curve中的內(nèi)存管理

發(fā)布時(shí)間:2022-01-12 16:30:48 來源:億速云 閱讀:131 作者:柒染 欄目:云計(jì)算

本篇文章給大家分享的是有關(guān)怎么分析Curve中的內(nèi)存管理,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

前言

Curve 實(shí)踐過程中遇到過幾次內(nèi)存相關(guān)的問題,與操作系統(tǒng)內(nèi)存管理相關(guān)的是以下兩次:

  1. chunkserver上內(nèi)存無法釋放

  2. 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)存管理之前,首先簡要介紹下內(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)程可操作的用戶空間,形式如下圖。

怎么分析Curve中的內(nèi)存管理

現(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
  1. 上面輸出中進(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)閉。

  2. 接下來 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)限為可讀可寫的段。

  3. 再往下 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ī)偏移。

  4. 接著 0x7f6124000000 開始,對應(yīng)的是上圖 mmap 內(nèi)存映射區(qū)域,這一區(qū)域包含動(dòng)態(tài)庫、用戶申請的大片內(nèi)存等。到這里我們可以看到HeapMemory Mapping Region都可以用于程序中使用malloc動(dòng)態(tài)分配的內(nèi)存,在下一節(jié)內(nèi)存分配策略中會(huì)有展開,也是本文關(guān)注重點(diǎn)。

  5. 接著 0x7fffffd19000 開始是??臻g,一般有數(shù)兆字節(jié)。

  6. 最后 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)用。這里不具體展開。

內(nèi)存分配策略

我們平時(shí)使用malloc分配出來的內(nèi)存是在HeapMemory Mapping Region這兩個(gè)區(qū)域。mallloc 實(shí)際上由兩個(gè)系統(tǒng)調(diào)用完成:brkmmap

  • 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)該具有以下特征:

  1. 額外的空間損耗量盡量少。比如應(yīng)用程序只需要5k內(nèi)存,結(jié)果分配器給他分配了10k,會(huì)造成空間的浪費(fèi)。

  2. 分配的速度盡可能快。

  3. 盡量避免內(nèi)存碎片。下面我們結(jié)合圖來直觀的感受下內(nèi)存碎片。

  4. 通用性、兼容性、可移植性、易調(diào)試。

我們通過下面一幅圖直觀說明下 glibc 默認(rèn)的內(nèi)存管理器 ptmalloc 在單線程情況下堆內(nèi)存的回收和分配:

怎么分析Curve中的內(nèi)存管理

  1. malloc(30k)通過系統(tǒng)調(diào)用 brk 擴(kuò)展堆頂?shù)姆绞椒峙鋬?nèi)存。

  2. malloc(20k)通過系統(tǒng)調(diào)用 brk 繼續(xù)擴(kuò)展堆頂。

  3. malloc(200k)默認(rèn)情況下請求內(nèi)存大于 128K (由M_MMAP_THRESHOLD確定,默認(rèn)大小為128K,可以調(diào)整),就利用系統(tǒng)調(diào)用 mmap分配內(nèi)存。

  4. 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)存碎片。

  5. free(20k)這部分空間應(yīng)用程序釋放后,ptmalloc 會(huì)把剛才的 20k 和 30k 的區(qū)域合并,如果堆頂空閑超過M_TRIM_THREASHOLD,會(huì)把這塊區(qū)域收縮歸還給操作系統(tǒng)。

  6. 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ì)在HeapMemory 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 的內(nèi)存管理

Curve 中選擇了兩種分配器:ptmallocjemalloc。其中 MDS 使用默認(rèn)的 ptmalloc,Chunkserver 和 Client 端使用 jemalloc。

本文開頭提到的兩個(gè)問題在這里進(jìn)行說明。首先是MDS內(nèi)存緩慢增長,現(xiàn)象是每天增長 3G。這個(gè)問題分析的過程如下:

  1. 首先是使用pmap查看內(nèi)存分布。我們用 pmap 查看內(nèi)存緩慢增長的 curve-mds 內(nèi)存分配情況,發(fā)現(xiàn)在 Memory Mapping Region 存在著大量分配的 64M 內(nèi)存,且觀察一段時(shí)間后都不釋放還在一直分配。從這里懷疑存在內(nèi)存泄露。

  2. 然后查看應(yīng)用上請求的壓力情況。查看MDS 上相關(guān)的業(yè)務(wù) metric,發(fā)現(xiàn) MDS 上的壓力都很小,一些控制面 rpc 的 iops 在幾百左右,不應(yīng)該是業(yè)務(wù)壓力較大導(dǎo)致的。

  3. 接下來查看 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)。

  4. 根據(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è)問題分析的過程如下:

  1. 首先分析內(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 。

  2. 查看對應(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 無法釋放。

  3. 分析驗(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è)資訊頻道。

向AI問一下細(xì)節(jié)

免責(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)容。

AI