Redis分配內存的一些疑惑

以下部分只是作者的臆測,

還沒有的到證實,

因為作者的C語言水平有限,還望有高手能夠出來指導,

謝謝..

疑惑1

最近在「研究」Redis的源碼,剛看到內存管理[zmalloc]的部分,發現其中的一段代碼很是奇怪(可能在我看來很奇怪),代碼如下:

#define update_zmalloc_stat_alloc(__n) do { size_t _n = (__n); //重點在這裡 if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); if (zmalloc_thread_safe) { update_zmalloc_stat_add(_n); } else { used_memory += _n; } } while(0)

這個函數的功能是每次Redis申請內存的時候,更新下Redis所申請的內存總數`used_memory`.但是其中一行代碼:

if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n(sizeof(long)-1));

它的意思是將申請的內存位元組數目對於sizeof(long)來向上取整,即總是取sizeof(long)的倍數.

解釋(機器字長)

CPU在讀取內存的時候, 並不是按照一個位元組一個位元組的來讀取, 而是一次讀取一個`機器字`的長度. 例如 32 位的CPU一次讀取 32 bits的數據, 也就是 32 / 8 = 4 Bytes(4個位元組)的內存信息.

zmalloc 中這樣來處理分配內存的大小, 是為了在為同一個數據分配的內存, 能夠在最少的 CPU 時鐘周期里讀取完成.

疑惑2

同樣是分配內存空間的代碼中, 每次分配內存的時候會在內存的起始位置加上 PREFIX_SIZE大小的內存, 並且存放的是此次`分配內存的大小`.

PREFIX_SIZE的定義如下:

#ifdef HAVE_MALLOC_SIZE#define PREFIX_SIZE (0)#else#if defined(__sun) || defined(__sparc) || defined(__sparc__)#define PREFIX_SIZE (sizeof(long long))#else#define PREFIX_SIZE (sizeof(size_t))#endif#endif

不同的OS結構下面, 其值不一樣.

對於分配內存的時候, 多分配 `PREFIX_SIZE` 位元組的內存空間並且存儲此次分配內存空間的大小, 代碼如下:

void *zmalloc(size_t size) { //這裡可見分內的時候, 會多分配 PREFIX_SIZE 位元組 void *ptr = malloc(size + PREFIX_SIZE); if(!ptr) zmalloc_oom_handler(size);#ifdef HAVE_MALLOC_SIZE //這裡表示 OS 會自己統計已分配內存的大小 update_zmalloc_stat_alloc(zmalloc_size(ptr)); return ptr;#else *((size_t*)ptr) = size; //轉換指針 ptr 的類型, 並且在指針開始的 PREFIX_SIZE 個位元組中賦值 size update_zmalloc_stat_alloc(size + PREFIX_SIZE); // 轉換指針 ptr 的類型為 char* , 操作指針偏移的時候, 便宜量保證只有一個位元組 // // 通過之前的代碼可以看見, 在申請內存的時候總是會多申請 PREFIX_SIZE 個位元組的空間, // 並且在這些空間裡面保存了申請內存空間的大小 size // //可見這裡返回的指針已經向右偏移了 PREFIX_SIZE 個位元組, 也就是實際的內存開始位置 return (char*)ptr + PREFIX_SIZE;#endif}

解釋

這樣做的的目的是為了能夠快速的獲取指針指向變數的內存空間的大小.

例如, 在獲取字元串所佔的內存空間的時候, 我們只需要將指針左移 PREFIX_SIZE位元組, 然後獲取裡面 size 的值即可, 時間複雜度是常數級別 O(1).

最後

這裡附加一張通過 zmalloc 分配內存之後的內存圖, 當然圖片是從網上找的. 點擊[這裡](Redis中的內存管理:關於zmalloc - 程序園)查看原圖.

:

Redis中的內存管理:關於zmalloc - 程序園
推薦閱讀:

Linux 中的「大內存頁」(hugepage)是個什麼?
從C++的RAII理解智能指針的思路(二)
九. 內核的內存分配
內核如何管理內存

TAG:Redis | 內存管理 |