本文以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占用的位元組傳回上層使用。
/* 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;
}