現在的位置: 首頁 > 資料庫 > 正文

Redis在內存分配和使用統計方面有哪些技巧

2020年07月02日 資料庫 ⁄ 共 3753字 ⁄ 字型大小 評論關閉

  Redis中到處都會進行內存分配操作。為了屏蔽不同平台之間的差異,以及統計內存佔用量等,Redis對內存分配函數進行了一層封裝,程序中統一使用zmalloc,zfree一系列函數,位於zmalloc.h,zmalloc.c文中。下面學步園小編來講解下Redis在內存分配和使用統計方面有哪些技巧?

  Redis在內存分配和使用統計方面有哪些技巧

  具體來說就是:

  若系統中存在Google的TC_MALLOC庫,則使用tc_malloc一族函數代替原本的malloc一族函數。

  若當前系統是Mac系統,則使用中的內存分配函數。

  其他情況,在每一段分配好的空間前頭,同時多分配一個定長的欄位,用來記錄分配的空間大小。

  源代碼分別在 config.h 和 zmalloc.c 中:

  /* config.h */

  #if defined(USE_TCMALLOC)

  #include

  #if TC_VERSION_MAJOR >= 1 && TC_VERSION_MINOR >= 6

  #define HAVE_MALLOC_SIZE 1

  #define redis_malloc_size(p) tc_malloc_size(p)

  #endif

  #elif defined(__APPLE__)

  #include

  #define HAVE_MALLOC_SIZE 1

  #define redis_malloc_size(p) malloc_size(p)

  #endif

  /* zmalloc.c */

  #ifdef HAVE_MALLOC_SIZE

  #define PREFIX_SIZE (0)

  #else

  #if defined(__sun)

  #define PREFIX_SIZE (sizeof(long long))

  #else

  #define PREFIX_SIZE (sizeof(size_t))

  #endif

  #endif

  因為 tc_malloc 和 Mac平台下的 malloc 函數族提供了計算已分配空間大小的函數(分別是tc_malloc_size和malloc_size),所以就不需要單獨分配一段空間記錄大小了。而針對linux和sun平台則要記錄分配空間大小。對於linux,使用sizeof(size_t)定長欄位記錄;對於sun os,使用sizeof(long long)定長欄位記錄。也就是上邊源碼中的 PREFIX_SIZE 宏。

  那麼這個記錄有什麼用呢?答案是,為了統計當前進程到底佔用了多少內存。在 zmalloc.c 中,有這樣一個靜態變數:

  static size_t used_memory = 0;

  它記錄了進程當前佔用的內存總數。每當要分配內存或是釋放內存的時候,都要更新這個變數。因為分配內存的時候,可以明確知道要分配多少內存。但是釋放內存的時候,(對於未提供malloc_size函數的平台)僅通過指向要釋放內存的指針是不能知道釋放的空間到底有多大的。這個時候,上邊提到的PREFIX_SIZE定長欄位就起作用了,可以通過其中記錄的內容得到空間的大小。zmalloc函數如下(去掉無關代碼):

  void *zmalloc(size_t size) {

  void *ptr = malloc(size+PREFIX_SIZE);

  if (!ptr) zmalloc_oom(size);

  *((size_t*)ptr) = size;

  update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);

  return (char*)ptr+PREFIX_SIZE;

  #endif

  }

  Redis在內存分配和使用統計方面有哪些技巧

  看到在分配空間的時候,空間大小是size+PREFIX_SIZE。對於mac系統或是使用tc_malloc的情況,PREFIX_SIZE 為0。之後將ptr指針指向的空間前size_t中記錄分配空間的大小。最後返回的是越過記錄區的指針。zfree函數類似(去掉無關代碼):

  void zfree(void *ptr) {

  void *realptr;

  size_t oldsize;

  if (ptr == NULL) return;

  realptr = (char*)ptr-PREFIX_SIZE;

  oldsize = *((size_t*)realptr);

  update_zmalloc_stat_free(oldsize+PREFIX_SIZE);

  free(realptr);

  #endif

  }

  先將指針向前移動PREFIX_SIZE,然後取出分配空間時保存的空間長度。最後free整個空間。

  update_zmalloc_stat_alloc(__n,__size) 和 update_zmalloc_stat_free(__n) 這兩個宏負責在分配內存或是釋放內存的時候更新used_memory變數。定義成宏主要是出於效率上的考慮。將其還原為函數,就是下邊這個樣子:

  void update_zmalloc_stat_alloc(__n,__size)

  {

  do {

  size_t _n = (__n);

  size_t _stat_slot = (__size < ZMALLOC_MAX_ALLOC_STAT) ? __size : ZMALLOC_MAX_ALLOC_STAT;   if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1));   if (zmalloc_thread_safe) {   pthread_mutex_lock(&used_memory_mutex);   used_memory += _n;   zmalloc_allocations[_stat_slot]++;   pthread_mutex_unlock(&used_memory_mutex);   } else {   used_memory += _n;   zmalloc_allocations[_stat_slot]++;   }   } while(0)   }   void update_zmalloc_stat_free(__n)   {   do {   size_t _n = (__n);   if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1));   if (zmalloc_thread_safe) {   pthread_mutex_lock(&used_memory_mutex);   used_memory -= _n;   pthread_mutex_unlock(&used_memory_mutex);   } else {   used_memory -= _n;   }   } while(0)   }   代碼中除了更新used_memory變數外,還有幾個要關注的地方:   先對_n的低位向上取整,最後_n變為sizeof(long)的倍數,比如對於32位系統,sizeof(long) == 100(二進位),_n向上取整之後,低兩位都變為0。   如果進程中有多個線程存在,則在更新變數的時候要加鎖。   在zmalloc函數中還有一個統計量要更新:zmalloc_allocations[]。   在 zmalloc.c 中,zmalloc_allocations是這樣定義的:   size_t zmalloc_allocations[ZMALLOC_MAX_ALLOC_STAT+1];   其作用是統計程序分配內存時,對不同大小空間的請求次數。統計的空間範圍從1位元組到256位元組,大於256位元組的算為256。統計結果通過調用 zmalloc_allocations_for_size 函數返回:   size_t zmalloc_allocations_for_size(size_t size) {   if (size > ZMALLOC_MAX_ALLOC_STAT) return 0;

  return zmalloc_allocations[size];

  }

  另一個對內存使用量的統計通過調用 zmalloc_used_memory 函數返回:

  size_t zmalloc_used_memory(void) {

  size_t um;

  if (zmalloc_thread_safe) pthread_mutex_lock(&used_memory_mutex);

  um = used_memory;

  if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex);

  return um;

  }

  另外 zmalloc.c 中,還針對不同的系統實現了 zmalloc_get_rss 函數,在linux系統中是通過讀取/proc/$pid/stat文件獲得系統統計的內存佔用量。

  以上就是關於「Redis在內存分配和使用統計方面有哪些技巧」的內容,希望對大家有用。更多資訊請關注學步園。學步園,您學習IT技術的優質平台!

抱歉!評論已關閉.