Redis在内存分配和使用统计的技巧有哪些

61次阅读
没有评论

共计 3471 个字符,预计需要花费 9 分钟才能阅读完成。

本篇内容主要讲解“Redis 在内存分配和使用统计的技巧有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“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 在内存分配和使用统计的技巧有哪些”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-15发表,共计3471字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)