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

  具体来说就是:

  若系统中存在Google的TC_MALLOC库,则使用tc_malloc一族函数代替原本的malloc一族函数。

  若当前系统是Mac系统,则使用中的内存分配函数。

Redis内存分配和使用:七个技巧让你更好地使用

  其他情况,在每一段分配好的空间前头,同时多分配一个定长的字段,用来记录分配的空间大小。

  源代码分别在 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是一个非常流行的内存数据库,其出色的性能和高速的响应速度使得越来越多的开发者使用Redis作为应用程序的缓存存储。然而,对于Redis的内存分配和使用,可能有一些开发者仍然存在一些疑问。本文将为大家介绍七个技巧,帮助你更好地管理你的Redis内存。
1. 监控内存的使用情况
Redis自己的monitor命令可以打印出所有处理Redis请求的详细过程,包括内存使用情况,以及处理每个请求时所消耗的时间和资源。在Redis的开发和调试过程中,建议使用monitor命令监控内存的使用情况,以便及时发现内存使用情况异常。
2. 慎用大量内存的资源
由于Redis的内存缓存限制,建议进行内存限制规划,避免Redis单实例使用大量内存资源导致缓存命中率下降。
3. 存储小数据原则
使用Redis存储数据时,应该尽可能的使用小数据,避免存储大数据、大文件等。不仅可以节省内存资源,还可以提高应用程序的性能。
4. 使用Redis中的数据类型
Redis内置了多种数据类型,如字符串、哈希表、列表、集合和有序集合。开发者应该选择合适的数据类型,避免存储大量重复的数据,以便更好地使用内存资源。
5. 合理设置过期时间
使用Redis时,可以通过设置数据的过期时间,让Redis自动清除不需要的数据,避免占用过多的内存空间。合理设置过期时间能有效减少内存占用,提高缓存的利用率。
6. 合理采用持久化机制
Redis提供的持久化机制包括快照和AOF(append-only file),可以将Redis的数据定期或实时写入到硬盘中。通过合理使用持久化机制,可以减少Redis节点崩溃时数据丢失的可能性,并根据实际需求选择合适的持久化方式。
7. 合理使用内存优化参数
Redis提供了一些内存优化参数,如maxmemory、maxmemory-policy和mem-overhead等,可以帮助开发者更好的控制Redis的内存使用情况。开发者应该根据实际需求,合理配置这些参数,以便更好的管理内存资源。
总结
Redis作为一种非常流行的内存数据库,其高性能和高速的响应速度受到开发者的青睐。通过本文介绍的七个技巧,可以帮助开发者更好地管理Redis的内存使用情况,提高缓存命中率和应用程序的性能。当然,对于Redis的内存使用,还有很多需要了解和研究的地方,开发者需要不断积累经验,进行针对性的优化和调整。