? ? ? ?內(nèi)存分配的代碼寫在zmalloc.c和zmalloc.h中尚猿。原理是對(duì)底層內(nèi)存分配方式的再封裝。除此之外楣富,redis沒(méi)有對(duì)內(nèi)存進(jìn)行額外的操作凿掂,因此,內(nèi)存分配器的性能和碎片化率會(huì)對(duì)redis造成一些性能上的影響。其底層內(nèi)存分配會(huì)根據(jù)宏的選擇不同而有所不同庄萎。如果定義了USE_TCMALLOC踪少,則使用tcmalloc;如果定義了USE_JEMALLOC糠涛,則使用jemalloc援奢;否則如果系統(tǒng)自帶c運(yùn)行庫(kù),將會(huì)使用系統(tǒng)自帶的malloc進(jìn)行內(nèi)存分配忍捡;最后才會(huì)使用redis自己的內(nèi)存分配函數(shù)集漾。
redis會(huì)通過(guò)定義宏 HAVE_MALLOC_SIZE為1 來(lái)表示使用的是其他庫(kù)的內(nèi)存分配函數(shù)。
? ? ? ?封裝的底層函數(shù):
malloc_usable_size(p)//返回p對(duì)應(yīng)內(nèi)存的大小
malloc(size)//分配堆內(nèi)存砸脊,內(nèi)容沒(méi)有初始化
calloc(count,size)//在malloc基礎(chǔ)上具篇,將內(nèi)存初始化為0
realloc(ptr,size)
free(ptr)
? ? ? ?對(duì)于特定版本的JEMALLOC,redis實(shí)現(xiàn)了內(nèi)存的碎片化處理凌埂。
? ? ? ?zmalloc里主要的兩個(gè)宏
#define update_zmalloc_stat_alloc(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
atomicIncr(used_memory,__n); \
} while(0)
#define update_zmalloc_stat_free(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
atomicDecr(used_memory,__n); \
? ? ? ?上面兩個(gè)都進(jìn)行了原子操作驱显,保證線程安全;同時(shí)if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)) 確保了64位機(jī)上8字節(jié)對(duì)齊(這個(gè)技巧運(yùn)用了位操作瞳抓,效率很高埃疫;同時(shí)字節(jié)對(duì)齊的單位取決于系統(tǒng),即所謂的軟編碼)孩哑。
? ? ? ?zmalloc里的重要變量:
static size_t used_memory = 0;
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
? ? ? ?zmalloc主要函數(shù)如下:
size_t zmalloc_usable(void *ptr)//返回內(nèi)存大小(不包含prefix的大小)
size_t zmalloc_size(void *ptr)//返回內(nèi)存大小(包含prefix的大小)
void *zmalloc(size_t size);
void *zcalloc(size_t size);
void *zrealloc(void *ptr, size_t size);
void zfree(void *ptr);
char *zstrdup(const char *s);
size_t zmalloc_used_memory(void);
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
//獲得系統(tǒng)的配置信息
size_t zmalloc_get_rss(void);//實(shí)際使用的物理內(nèi)存
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);//得到指定pid指定field對(duì)應(yīng)的值
size_t zmalloc_get_private_dirty(long pid);//上一個(gè)函數(shù)的filed為”Private_Dirty"
int zmalloc_get_allocator_info(size_t *allocated, size_t *active, size_t *resident);//得到已經(jīng)申請(qǐng)了內(nèi)存數(shù)栓霜,活躍的,長(zhǎng)期存在的內(nèi)存數(shù)
size_t zmalloc_get_memory_size(void);//獲得RAM的大小
? ? ? ?redis的內(nèi)存分配方式如下:
? ? ? ?prefix存儲(chǔ)buf的大小臭笆。這種管理方式類似redis中的sds管理方式叙淌。如果使用了外部庫(kù)的內(nèi)存分配函數(shù),PREFIX_SIZE為0愁铺。