redis基础数据结构(二) 内存管理模块

redis可选内存管理方式为tcmalloc或jemalloc,用宏控制,一般用jemalloc性能最好,底层调用remalloc接口,redis的内存管理模块只是封装函数,内存管理在zmalloc.h和zmalloc.c中。

zmalloc.c中定义一个全局变量used_memory和两个用于管理user_memory的宏,如下

#define update_zmalloc_stat_alloc(__n) do { \
    size_t _n = (__n); \
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
    atomicIncr(used_memory,__n); \
} while(0)

#define update_zmalloc_stat_free(__n) do { \
    size_t _n = (__n); \
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
    atomicDecr(used_memory,__n); \
} while(0)

static size_t used_memory = 0;
pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;

其中atomicIncr和atomicDecr是原子操作,通过互斥锁实现,内存补齐使用位操作以保证性能,used_memory保存的是实际使用的内存大小

内存分配函数zmalloc:

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
}

给ptr分配内存时,增加size_t大小内存,用于保存实际使用的内存大小,返回给调用者的指针越过这个大小的地址。其余内存管理函数calloc和realloc等实现方式和malloc类似

进程内存管理:

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/<pid>/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;
}
通过读取/proc/pid/stat中的rss字段,涉及文件读取,显然性能很差。内存碎片率用rss/used_memory计算,此外zmalloc模块还提供了读取smap等内存接口,具体含义参见linux进程内存管理机制

猜你喜欢

转载自blog.csdn.net/kdb_viewer/article/details/80672862