具體來說就是:
若係統中存在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 HAVE_MALLOC_SIZE 1
#define HAVE_MALLOC_SIZE 1
)>
#endif #elif defined(__APPLE__) #include# #define HAVE_MALLOC_SIZE 1# #define HAVE_MALLOC_SIZE 1# #define HAVE_MALLOC_SIZE 1#『 ) #endif /* zmalloc.c */ #ifdef HAVE_MALLOC_SIZE 」 else #if defined(__sun) #define PREFIX_SIZE (sizeof(long long)) #else[]] )) #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);1IX_
#endif
}
Redis在記憶體分配和使用統計方面有哪些技巧
#當分配空間時,注意空間大小要加上PREFIX_SIZE 。當運行在Mac系統或使用tc_malloc時,PREFIX_SIZE的值為零。接下來會將指標ptr所指向的記憶體區塊的前面size_t個位元組用於記錄該記憶體區塊的分配大小。最後回傳的是越過記錄區的指標。 zfree函數類似(去掉無關程式碼):
void zfree(void *ptr) {
void *realptr;
size_t oldsize;
## ptr == NULL) return; realptr = (char*)ptr-PREFIX_SIZE; oldsize = *((size_t*)realptr);IX_fDate_
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)
{
多 {
## {###### );###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];
}
;
## }###
## size_t zmalloc_used_memory(void) { size_t um; if (zmalloc_thread_safe) pthread_mutex_# if (zmalloc_thread_safe) pthread_mutex_# if (zmalloc_thread_safe) pthread_mutex_lock(&used_mlock1(&used_m # if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex); return um; } return um; } n 子。系統中是透過讀取/proc/$pid/stat檔案取得系統統計的記憶體佔用量。 ###以上是Redis在記憶體分配和使用統計的技巧有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!