您好,登錄后才能下訂單哦!
這篇“Redis的zmalloc函數實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Redis的zmalloc函數實例分析”文章吧。
我們直接來看 Redis 源碼(不是最新版本)中自定義的 zmalloc 函數,該函數與 malloc 等常規函數的使用方式完全一致,不同的在于其內部的具體實現細節。
void *zmalloc(size_t size) {
// 分配內存;
void *ptr = malloc(size + PREFIX_SIZE);
// 分配失敗拋出異常;
if (!ptr) zmalloc_oom_handler(size);
// 系統是否可以使用”malloc_size“函數?
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
// 在數據域保存分配數據的實際大小;
*((size_t*)ptr) = size;
// 計算對齊后的內存使用大小,并更新”used_memory“變量;
update_zmalloc_stat_alloc(size + PREFIX_SIZE);
// 返回數據體的初始位置;
return (char*)ptr + PREFIX_SIZE;
#endif
}
其實,標準庫中的 malloc 函數已經能夠自動為分配的內存實現對齊,因此 zmalloc 方法在這里其主要目的是為了能夠精確地計算每一次數據存儲時所分配的內存大小。在每一次分配內存時,zmalloc 都會在該次分配的數據內存大小的基礎上再加上一個 PREFIX_SIZE 大小的額外內存空間,這個 PREFIX_SIZE 宏代表了當前系統的最大內存尋址空間大小(size_t),其依賴于具體系統的類型不同而不同。這里我們可以簡稱這個 PREFIX_SIZE 大小的空間為一個存儲單元的“數據頭”部分。
初版 Redis 的存儲單元結構
如上圖所示,通過 *((size_t*)ptr) = size; 語句,Redis 在當前分配內存塊的前 PREFIX_SIZE 個字節,即數據頭內存儲了本次實際分配的數據塊大小,而在后面 ”size“ 大小的內存空間中才真正存放了二進制的數據實體。在這里名為 update_zmalloc_stat_alloc 的函數在其內部會維護一個名為 used_memory 的全局變量,該變量累加了每次新分配的內存大小。函數在最后返回了一個偏移的指針,指向了當前分配內存的數據體部分。update_zmalloc_stat_alloc 函數的具體實現細節如下。
#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)
這里需要注意的重點是 _n += sizeof(long)-(_n&(sizeof(long)-1)); 這行語句。整個宏函數首先判斷本次分配的內存大小是否為 sizeof(long) 大小的整數倍(64位機對應著8字節的內存對齊;32位機則對應著4字節的內存對齊),如果不是則通過我們之前給出的語句在該數據段后添加相應的占位空間來補足位數以滿足內存對齊(4/8字節)的要求。最后的 atomicIncr 函數用來在保證線程安全的情況下更新全局的 used_memory 變量值。
而該版本 Redis 中內存釋放與其內存分配的過程則正好相反。如下所示代碼為對應 ”zfree“ 函數的實現細節。首先該函數通過 (char*)ptr-PREFIX_SIZE 語句(向內存低地址移動)指向了包含有該數據塊實際占用大小的數據域首地址,然后通過 *((size_t*)realptr) 語句獲得到了該數據塊分配的真實內存大小(不包含內存對齊區域)。最后再通過 update_zmalloc_stat_free 函數來更新全局變量 used_memory 的值,并釋放該段內存。
void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
size_t oldsize;
#endif
if (ptr == NULL) return;
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_free(zmalloc_size(ptr));
free(ptr);
#else
realptr = (char*)ptr-PREFIX_SIZE;
oldsize = *((size_t*)realptr);
update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
free(realptr);
#endif
}
如下所示,這里如果我們再來看 update_zmalloc_stat_free 函數的實現細節,你會發現它與之前的 update_zmalloc_stat_alloc 函數其執行過程類似。通過計算需要補足的內存字節大小,并從 used_memory 變量中減去相應大小的內存空間,即可實現對內存空間使用率的精確計算。
#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); \
} while(0)
以上就是關于“Redis的zmalloc函數實例分析”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。