Redis学习(一):zmalloc

zmalloc.{c,h}是对Redis内存进行一系列管理的文件,包括对malloc的封装,以及一些内存的状态数据分析。

这里面有一个比较重要的变量叫used_memory,他记录了Redis一共分配了多少的内存,后面的大部分函数都是跟这个变量打交道。

zmalloc zcalloc zrealloc zmalloc_size zfree

这些函数都是封装了C函数库中的malloc calloc realloc free,主要是为了记录Redis分配的内存大小,虽然malloc本身会在首地址前面记录分配的大小(不然free怎么知道要释放多少内存),但是这个大小程序员并不能直接获取,所以需要封装记录。

void *zmalloc(size_t size) {
    void *ptr = malloc(size+PREFIX_SIZE);

    if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
    update_zmalloc_stat_alloc(zmalloc_size(ptr));
    return ptr;
#else
    *((size_t*)ptr) = size;
    update_zmalloc_stat_alloc(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
#endif
}

在分配内存时多分配PREFIX_SIZE大小用于记录size的大小,update_zmalloc_stat_alloc是用来更新Redis一共分配了多少内存,最后返回地址需要加PREFIX_SIZE来返回给上层,因为PREFIX_SIZE这部分对上层是透明的。zcalloc zrealloc这两个函数与zmalloc类似。

size_t zmalloc_size(void *ptr) {
    void *realptr = (char*)ptr-PREFIX_SIZE;
    size_t size = *((size_t*)realptr);
    /* Assume at least that all the allocations are padded at sizeof(long) by
     * the underlying allocator. */
    if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
    return size+PREFIX_SIZE;
}

zmalloc_size用于获取内存的大小,只需要将首地址减去PREFIX_SIZE就可以读取到分配时存入的分配内存大小了。

void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
    void *realptr;
    size_t oldsize;
#endif

    if (ptr == NULL) return;
#ifdef HAVE_MALLOC_SIZE
    update_zmalloc_stat_free(zmalloc_size(ptr));
    free(ptr);
#else
    realptr = (char*)ptr-PREFIX_SIZE;
    oldsize = *((size_t*)realptr);
    update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
    free(realptr);
#endif
}

释放空间记得吧前面PREFIX_SIZE部分也要释放,然后用update_zmalloc_stat_free更新used_memory。

RSS

RSS指实际内存占用大小

size_t zmalloc_get_rss(void) {
    int page = sysconf(_SC_PAGESIZE);
    size_t rss;
    char buf[4096];
    char filename[256];
    int fd, count;
    char *p, *x;

    snprintf(filename,256,"/proc/%d/stat",getpid());
    if ((fd = open(filename,O_RDONLY)) == -1) return 0;
    if (read(fd,buf,4096) <= 0) {
        close(fd);
        return 0;
    }
    close(fd);

    p = buf;
    count = 23; /* RSS is the 24th field in /proc//stat */
    while(p && count--) {
        p = strchr(p,' ');
        if (p) p++;
    }
    if (!p) return 0;
    x = strchr(p,' ');
    if (!x) return 0;
    *x = '\0';

    rss = strtoll(p,NULL,10);
    rss *= page;
    return rss;
}

这个函数是通过打开系统文件然后进行一系列的处理获取这个进程(Redis)的RSS。

float zmalloc_get_fragmentation_ratio(size_t rss) {
    return (float)rss/zmalloc_used_memory();
}

通过rss和used_memory可以计算碎片率。

Private_Dirty

size_t zmalloc_get_private_dirty(void) {
    char line[1024];
    size_t pd = 0;
    FILE *fp = fopen("/proc/self/smaps","r");

    if (!fp) return 0;
    while(fgets(line,sizeof(line),fp) != NULL) {
        if (strncmp(line,"Private_Dirty:",14) == 0) {
            char *p = strchr(line,'k');
            if (p) {
                *p = '\0';
                pd += strtol(line+14,NULL,10) * 1024;
            }
        }
    }
    fclose(fp);
    return pd;
}

获取Private_Dirty的值,这个值我的理解是被多个进程共享的内存。

最后

还有一些oom的函数和stl中类似就不写了。这个文件还算简单,接下来我会看Redis的5种数据类型。

你可能感兴趣的:(Redis)