【redis源码】(一)Zmalloc

 
Zmalloc是redis的基础,redis源码的阅读从Zmalloc开始,相信这个一个愉快的旅程,读优秀的代码,就像听音乐~ 好了开始吧
 
头文件 Zmalloc.h,没什么好说的,声明了一些函数,具体的实现见Zmalloc.c
 
   1:  #ifndef _ZMALLOC_H
   2:  #define _ZMALLOC_H
   3:   
   4:  void *zmalloc(size_t size);
   5:  void *zcalloc(size_t size); 
   6:  void *zrealloc(void *ptr, size_t size);
   7:  void zfree(void *ptr);
   8:  char *zstrdup(const char *s);
   9:  size_t zmalloc_used_memory(void);
  10:  void zmalloc_enable_thread_safeness(void);
  11:  float zmalloc_get_fragmentation_ratio(void);
  12:  size_t zmalloc_get_rss(void);
  13:   
  14:  #endif /* _ZMALLOC_H */

Zmalloc.c
   1:  #include <stdio.h>
   2:  #include <stdlib.h>
   3:  #include <string.h>
   4:  #include <pthread.h>
   5:  #include "config.h"
   6:  #include "zmalloc.h"
   7:   
   8:   
   9:  //PREFIX_SIZE用来记录malloc拿到的内存块的size,如果使用了google的tcmalloc库或者苹果的环境,可以使用系统函数获得内存块的大小,就不用这个区域来记录
  10:  #ifdef HAVE_MALLOC_SIZE
  11:  #define PREFIX_SIZE (0)
  12:  #else
  13:  #if defined(__sun)
  14:  #define PREFIX_SIZE (sizeof(long long))
  15:  #else
  16:  #define PREFIX_SIZE (sizeof(size_t))
  17:  #endif
  18:  #endif
  19:   
  20:  /* Explicitly override malloc/free etc when using tcmalloc. */
  21:  //使用google的tcmalloc库作为底层的malloc函数
  22:  #if defined(USE_TCMALLOC)
  23:  #define malloc(size) tc_malloc(size)
  24:  #define calloc(count,size) tc_calloc(count,size)
  25:  #define realloc(ptr,size) tc_realloc(ptr,size)
  26:  #define free(ptr) tc_free(ptr)
  27:  #endif
  28:   
  29:  //Zmalloc会在全局静态变量里记录已经申请的内存大小 static size_t used_memory = 0;
  30:  #define update_zmalloc_stat_alloc(__n,__size) do { \
  31:      size_t _n = (__n); \
  32:      //将记录的内存大小补齐sizeof(long)的倍数
  33:      if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
  34:      if (zmalloc_thread_safe) { \
  35:          pthread_mutex_lock(&used_memory_mutex);  \
  36:          used_memory += _n; \
  37:          pthread_mutex_unlock(&used_memory_mutex); \
  38:      } else { \
  39:          used_memory += _n; \
  40:      } \
  41:  } while(0)
  42:   
  43:  #define update_zmalloc_stat_free(__n) do { \
  44:      size_t _n = (__n); \
  45:      if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
  46:      if (zmalloc_thread_safe) { \
  47:          pthread_mutex_lock(&used_memory_mutex);  \
  48:          used_memory -= _n; \
  49:          pthread_mutex_unlock(&used_memory_mutex); \
  50:      } else { \
  51:          used_memory -= _n; \
  52:      } \
  53:  } while(0)
  54:   
  55:  static size_t used_memory = 0;
  56:  static int zmalloc_thread_safe = 0;
  57:  pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
  58:   
  59:  //如果申请内存失败,发送SIGABRT信号通知程序
  60:  static void zmalloc_oom(size_t size) {
  61:      fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
  62:          size);
  63:      fflush(stderr);
  64:      abort();
  65:  }
  66:   
  67:  //申请size大bytes的内存区域
  68:  void *zmalloc(size_t size) {
  69:      //实际申请size+PREFIX_SIZE大小的内存空间,其中,前PREFIX_SIZE的空间用来记录内存块大小
  70:      void *ptr = malloc(size+PREFIX_SIZE);
  71:   
  72:      if (!ptr) zmalloc_oom(size);
  73:  #ifdef HAVE_MALLOC_SIZE
  74:      update_zmalloc_stat_alloc(redis_malloc_size(ptr),size);
  75:      return ptr;
  76:  #else
  77:      //记录内存块大小
  78:      *((size_t*)ptr) = size;
  79:      update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
  80:      return (char*)ptr+PREFIX_SIZE;
  81:  #endif
  82:  }
  83:   
  84:  //申请size个sizeof(byte)大的内存区域
  85:  void *zcalloc(size_t size) {
  86:      void *ptr = calloc(1, size+PREFIX_SIZE);
  87:   
  88:      if (!ptr) zmalloc_oom(size);
  89:  #ifdef HAVE_MALLOC_SIZE
  90:      update_zmalloc_stat_alloc(redis_malloc_size(ptr),size);
  91:      return ptr;
  92:  #else
  93:      *((size_t*)ptr) = size;
  94:      update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);
  95:      return (char*)ptr+PREFIX_SIZE;
  96:  #endif
  97:  }
  98:   
  99:  //重新分配size大小的内存
 100:  void *zrealloc(void *ptr, size_t size) {
 101:  #ifndef HAVE_MALLOC_SIZE
 102:      void *realptr;
 103:  #endif
 104:      size_t oldsize;
 105:      void *newptr;
 106:   
 107:      if (ptr == NULL) return zmalloc(size);
 108:  #ifdef HAVE_MALLOC_SIZE
 109:      oldsize = redis_malloc_size(ptr);
 110:      newptr = realloc(ptr,size);
 111:      if (!newptr) zmalloc_oom(size);
 112:   
 113:      update_zmalloc_stat_free(oldsize);
 114:      update_zmalloc_stat_alloc(redis_malloc_size(newptr),size);
 115:      return newptr;
 116:  #else
 117:      realptr = (char*)ptr-PREFIX_SIZE;
 118:      oldsize = *((size_t*)realptr);
 119:      newptr = realloc(realptr,size+PREFIX_SIZE);
 120:      if (!newptr) zmalloc_oom(size);
 121:   
 122:      *((size_t*)newptr) = size;
 123:      update_zmalloc_stat_free(oldsize);
 124:      update_zmalloc_stat_alloc(size,size);
 125:      return (char*)newptr+PREFIX_SIZE;
 126:  #endif
 127:  }
 128:   
 129:  //释放ptr开始内存块,与zmalloc,zcalloc,zrealloc配对
 130:  void zfree(void *ptr) {
 131:  #ifndef HAVE_MALLOC_SIZE
 132:      void *realptr;
 133:      size_t oldsize;
 134:  #endif
 135:   
 136:      if (ptr == NULL) return;
 137:  #ifdef HAVE_MALLOC_SIZE
 138:      update_zmalloc_stat_free(redis_malloc_size(ptr));
 139:      free(ptr);
 140:  #else
 141:      realptr = (char*)ptr-PREFIX_SIZE;
 142:      oldsize = *((size_t*)realptr);
 143:      update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
 144:      free(realptr);
 145:  #endif
 146:  }
 147:   
 148:  //复制字符串
 149:  char *zstrdup(const char *s) {
 150:      size_t l = strlen(s)+1;
 151:      char *p = zmalloc(l);
 152:   
 153:      memcpy(p,s,l);
 154:      return p;
 155:  }
 156:   
 157:  //得到已申请内存块总大小
 158:  size_t zmalloc_used_memory(void) {
 159:      size_t um;
 160:   
 161:      if (zmalloc_thread_safe) pthread_mutex_lock(&used_memory_mutex);
 162:      um = used_memory;
 163:      if (zmalloc_thread_safe) pthread_mutex_unlock(&used_memory_mutex);
 164:      return um;
 165:  }
 166:   
 167:  //设置线程安全zmalloc开关,即操作前lock
 168:  void zmalloc_enable_thread_safeness(void) {
 169:      zmalloc_thread_safe = 1;
 170:  }
 171:   
 172:  /* Get the RSS information in an OS-specific way.
 173:   *
 174:   * WARNING: the function zmalloc_get_rss() is not designed to be fast
 175:   * and may not be called in the busy loops where Redis tries to release
 176:   * memory expiring or swapping out objects.
 177:   *
 178:   * For this kind of "fast RSS reporting" usages use instead the
 179:   * function RedisEstimateRSS() that is a much faster (and less precise)
 180:   * version of the funciton. */
 181:   
 182:  #if defined(HAVE_PROCFS)
 183:  #include <unistd.h>
 184:  #include <sys/types.h>
 185:  #include <sys/stat.h>
 186:  #include <fcntl.h>
 187:   
 188:  size_t zmalloc_get_rss(void) {
 189:      //获取runtime的信息,获取byte为单位的page大小
 190:      int page = sysconf(_SC_PAGESIZE);
 191:      size_t rss;
 192:      char buf[4096];
 193:      char filename[256];
 194:      int fd, count;
 195:      char *p, *x;
 196:   
 197:      snprintf(filename,256,"/proc/%d/stat",getpid());
 198:      if ((fd = open(filename,O_RDONLY)) == -1) return 0;
 199:      if (read(fd,buf,4096) <= 0) {
 200:          close(fd);
 201:          return 0;
 202:      }
 203:      close(fd);
 204:   
 205:      p = buf;
 206:      //获取第24列的占用page的数量信息
 207:      count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
 208:      while(p && count--) {
 209:          p = strchr(p,' ');
 210:          if (p) p++;
 211:      }
 212:      if (!p) return 0;
 213:      x = strchr(p,' ');
 214:      if (!x) return 0;
 215:      *x = '\0';
 216:   
 217:      rss = strtoll(p,NULL,10);
 218:      //得到占用系统内存总量
 219:      rss *= page;
 220:      return rss;
 221:  }
 222:  #elif defined(HAVE_TASKINFO)
 223:  #include <unistd.h>
 224:  #include <stdio.h>
 225:  #include <stdlib.h>
 226:  #include <sys/types.h>
 227:  #include <sys/sysctl.h>
 228:  #include <mach/task.h>
 229:  #include <mach/mach_init.h>
 230:   
 231:  size_t zmalloc_get_rss(void) {
 232:      task_t task = MACH_PORT_NULL;
 233:      struct task_basic_info t_info;
 234:      mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
 235:   
 236:      if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
 237:          return 0;
 238:      task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
 239:   
 240:      return t_info.resident_size;
 241:  }
 242:  #else
 243:  size_t zmalloc_get_rss(void) {
 244:      /* If we can't get the RSS in an OS-specific way for this system just
 245:       * return the memory usage we estimated in zmalloc()..
 246:       *
 247:       * Fragmentation will appear to be always 1 (no fragmentation)
 248:       * of course... */
 249:      return zmalloc_used_memory();
 250:  }
 251:  #endif
 252:   
 253:  /* Fragmentation = RSS / allocated-bytes */
 254:  float zmalloc_get_fragmentation_ratio(void) {
 255:      return (float)zmalloc_get_rss()/zmalloc_used_memory();
 256:  }
posted @ 2012-08-25 23:30  ~嘉言懿行~~我是煲仔饭~~  阅读(2722)  评论(0编辑  收藏  举报