您好,欢迎访问一九零五行业门户网

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在内存分配和使用统计方面有哪些技巧
当分配空间时,注意空间大小要加上prefix_size。当运行在mac系统或使用tc_malloc时,prefix_size的值为零。接下来会将指针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在内存分配和使用统计的技巧有哪些的详细内容。
其它类似信息

推荐信息