Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1108541
  • 博文数量: 143
  • 博客积分: 969
  • 博客等级: 准尉
  • 技术积分: 1765
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-30 12:09
文章分类

全部博文(143)

文章存档

2023年(4)

2021年(2)

2020年(4)

2019年(4)

2018年(33)

2017年(6)

2016年(13)

2014年(7)

2013年(23)

2012年(33)

2011年(14)

我的朋友

分类: 服务器与存储

2013-05-11 21:12:38

redis源码版本:2.6.12

内存分配的源码在zmlloc.c 和zmalloc.h
 在zmalloc.h中,定义了如下函数。
  1. void *zmalloc(size_t size);
  2. void *zcalloc(size_t size);
  3. void *zrealloc(void *ptr, size_t size);
  4. void zfree(void *ptr);
  5. char *zstrdup(const char *s);
  6. size_t zmalloc_used_memory(void);
  7. void zmalloc_enable_thread_safeness(void);
  8. void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
  9. float zmalloc_get_fragmentation_ratio(void);
  10. size_t zmalloc_get_rss(void);
  11. size_t zmalloc_get_private_dirty(void);
  12. void zlibc_free(void *ptr);
zmalloc,zcalloc,zrealloc和zfree分别对应c库中的malloc,calloc,realloc和free。zstrdup用于生成一个字符串的拷贝。后面的几个函数用于获取内存使用信息

在zmalloc.c中
  1. #if defined(USE_TCMALLOC)
  2. #define malloc(size) tc_malloc(size)
  3. #define calloc(count,size) tc_calloc(count,size)
  4. #define realloc(ptr,size) tc_realloc(ptr,size)
  5. #define free(ptr) tc_free(ptr)
  6. #elif defined(USE_JEMALLOC)
  7. #define malloc(size) je_malloc(size)
  8. #define calloc(count,size) je_calloc(count,size)
  9. #define realloc(ptr,size) je_realloc(ptr,size)
  10. #define free(ptr) je_free(ptr)
  11. #endif

 redis内存分配方式有三种:
   1、libc 的malloc系列方式
   2、google 的tcmalloc
   3、jemalloc
 tcmallloc和jemalloc性能要比malloc高很多,tcmalloc和jemalloc相比,jemalloc要比tcmalloc高一些。因此,redis默认使用jemalloc。
 zmalloc.c中有一个静态变量used_memory用来记录当前分配的内存总大小。 在redis-cli使用info命令看到的used_memory就是这里used_memory的统计出来的。
 在zmalloc函数中,实际分配内存长度是,是请求的长度+PREFIX_SIZE,PREFIX_SIZE是什么呢?PREFIX_SIZE其实是个宏,定义如下
  1. #ifdef HAVE_MALLOC_SIZE
  2. #define PREFIX_SIZE (0)
  3. #else
  4. #if defined(__sun) || defined(__sparc) || defined(__sparc__)
  5. #define PREFIX_SIZE (sizeof(long long))
  6. #else
  7. #define PREFIX_SIZE (sizeof(size_t))
  8. #endif
  9. #endif
如果定义了HAVE_MALLOC_SIZE,那么PREFIX_SIZE就为0。因为,tcmalloc和jemalloc库提供了函数malloc_size。具体查源码,这个比较简单。
也就是说,redis为了方便内存的管理,在分配一块内存之后,会将这块内存的大小存入内存块的头部。如下图。
        real_ptr    ret_ptr
            |                |
                  V                V
                          -------------------------------------------------------------------------
                          |    size      |  memory block                                              |
                          --------------------------------------------------------------------------
real_ptr是redis调用malloc后返回的指针。redis将内存块的大小size存入头部,size所占据的内存大小是已知的,为size_t类型的长度,然后返回ret_ptr。当需要释放内存的时候,ret_ptr被传给内存管理程序。通过ret_ptr,程序可以很容易的算出real_ptr的值,然后将real_ptr传给free释放内存。

值得一提的是zmalloc_get_rss()函数。这个函数用来获取进程的RSS。RSS(Resident Set Size),指实际使用物理内存(包含共享库占用的内存)。在linux系统中,可以通过读取/proc/pid/stat文件获取,pid为当前进程的进程号。读取到的不是byte数,而是内存页数。通过系统调用sysconf(_SC_PAGESIZE)可以获得当前系统的内存页大小。Unix系统貌似可以直接通过task_info直接获取,比linux系统简单的多。
获得进程的RSS后,可以计算目前数据的内存碎片大小,直接用rss除以used_memory。rss包含进程的所有内存使用,包括代码,共享库,堆栈等。但是由于通常情况下redis在内存中数据的量要远远大于这些数据所占用的内存,因此这个简单的计算还是比较准确的。

































阅读(2721) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~