天天看點

redis 0.091 源碼分析之zmalloc子產品

本文以redis官網能下載下傳的最早版本(0.091)源碼為基礎,官網下載下傳位址:https://download.redis.io/releases/redis-0.091.tar.gz

redis中的zmalloc主要是對c标準庫中的記憶體操作函數(malloc,free,realloc)進行封裝,加入used_memory記錄占用記憶體大小。

每個記憶體塊頭部加入一個size_t記錄上層申請記憶體的大小(不包括頭部size_t占用空間),使用size_t是為了更好的相容性,滿足不同系統記錄記憶體大小,最後把申請到記憶體的首位址偏移size_t占用的位元組傳回上層使用。

redis 0.091 源碼分析之zmalloc子產品
/* zmalloc - total amount of allocated memory aware version of malloc()
	...
 */

#include <stdlib.h>
#include <string.h>

// 靜态變量記錄使用記憶體大小,機關位元組
static size_t used_memory = 0;

// 申請記憶體,對于malloc
void *zmalloc(size_t size) {
	// 調用malloc申請記憶體,大小加上sizeof(size_t)
    void *ptr = malloc(size+sizeof(size_t));
	// 把size數值存入剛申請到的記憶體頭部
    *((size_t*)ptr) = size;
    // 更新使用記憶體大小
    used_memory += size+sizeof(size_t);
   	// 申請到的首位址偏移sizeof(size_t)個位元組再傳回上一層
   	// *注:因為指針加減法要對指針進行sizeof(ptr)計算後确定偏移量,這裡把ptr轉為char*,sizeof(char *)等于1個位元組,這樣就和sizeof(size_t)傳回的位元組數相對應
    return (char*)ptr+sizeof(size_t);
}

// 重新配置設定記憶體,對應realloc
void *zrealloc(void *ptr, size_t size) {
	// 真實記憶體首位址
    void *realptr;
    // 原大小
    size_t oldsize;
    // 新的真實記憶體首位址
    void *newptr;
	// 如果ptr為空則直接申請新的記憶體傳回
    if (ptr == NULL) return zmalloc(size);
    // 上層的首位址減去sizeof(size_t)個位元組,得到真實申請到的記憶體首位址,至于為什麼轉為char*請看zmallo的注釋
    realptr = (char*)ptr-sizeof(size_t);
    // 首位址的記憶體資料就是原來申請記憶體大小
    oldsize = *((size_t*)realptr);
    // 調用realloc重新配置設定記憶體,根據realloc特性newptr不一定等于realptr
    newptr = realloc(realptr,size+sizeof(size_t));
    // 申請不到傳回NULL代表失敗
    if (!newptr) return NULL;
	// 把新的size複制到新申請的記憶體的首位址
    *((size_t*)newptr) = size;
    // 更新使用記憶體大小
    used_memory -= oldsize;
    used_memory += size;
    // 和zmalloc一樣,首位址偏移後再傳回上層
    return (char*)newptr+sizeof(size_t);
}

// 釋放記憶體,對應free
void zfree(void *ptr) {
	// 真實記憶體首位址
    void *realptr;
    // 原記憶體大小
    size_t oldsize;
	// 如果為空指針則直接傳回
    if (ptr == NULL) return;
    // 計算真實記憶體首位址,和zrealloc一樣
    realptr = (char*)ptr-sizeof(size_t);
    // 讀取真實記憶體首位址資料
    oldsize = *((size_t*)realptr);
    // 更新記憶體,要加上sizeof(size_t)才是真實申請記憶體的大小
    used_memory -= oldsize+sizeof(size_t);
    // 釋放記憶體
    free(realptr);
}

// 字元串複制方法
char *zstrdup(const char *s) {
    size_t l = strlen(s)+1;
    char *p = zmalloc(l);

    memcpy(p,s,l);
    return p;
}

// 傳回使用記憶體大小
size_t zmalloc_used_memory(void) {
    return used_memory;
}