• 【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:  }
    喜欢一起简单,实用的东西,拒绝复杂花哨,我不是GEEK.
  • 相关阅读:
    《生命摆渡人》 读书笔记 读后感
    《饮食术》 读书笔记 读后感
    《天生有罪》读后感 读书笔记
    《内在动机》 读后感 读书笔记
    《从疾病到人心》读后感 读书笔记
    Python 入门书籍文档推荐及学习笔记总结
    JavaScript 入门书籍推荐及学习笔记总结 -- 《JavaScript权威指南》
    JavaScript中window.onload事件与document.ready事件的区别
    CentOS 7 中安装 MySQL 8 以及 MySQL 常用操作
    Python 杂记:argparse 模块
  • 原文地址:https://www.cnblogs.com/igloo1986/p/2657038.html
Copyright © 2020-2023  润新知