美文网首页
Redis zmalloc模块

Redis zmalloc模块

作者: 突击手平头哥 | 来源:发表于2020-12-03 23:47 被阅读0次

    Redis zmalloc模块

    zmalloc是处理redis内存的模块,主要涉及文件有:zmalloc、zmalloc.h、atomicvar.h, 本文从几个函数入手,简单说明该模块;同时这里面兼容了没有很多系统版本,目前仅分析普通Linux下的情况

    HAVE_MALLOC_SIZE宏定义

    #if defined(USE_TCMALLOC)
    #define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
    #include <google/tcmalloc.h>
    #if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
    #define HAVE_MALLOC_SIZE 1
    #define zmalloc_size(p) tc_malloc_size(p)
    #else
    #error "Newer version of tcmalloc required"
    #endif
    

      这里截取了一部分,优先采用tmalloc、jmalloc最后才使用标准的malloc函数;对于tmalloc、jmalloc我们不做分析处理,这里就当作是普通系统的malloc来分析

    zmalloc_size函数

    Redis中有统计内存大小的需求, 而正常来说malloc会进行一定的4/8字节对齐,所以不能简单的计算;该函数是系统API计算堆上分配的内存

    #define zmalloc_size(p) malloc_usable_size(p)

    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;                             //兼容没有malloc_size的情况, 在头部加一个PREFIX_SIZE存储大小
        update_zmalloc_stat_alloc(size+PREFIX_SIZE);
        return (char*)ptr+PREFIX_SIZE;
    #endif
    }
    
    //因为malloc对齐的缘故, 所以累计大小时需要向上扩展到4/8的倍数
    #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)
    
    • 内部实际分配内存还是用的malloc
    • 会将内存扩展到long大小的倍数(4/8), 并且记录下来; (_n&(sizeof(long)-1))就可以判断是否可以被sizeof(long)整除了
    • 使用atomicIncr累计, 具体实现稍后分析

    \color{red}{内存分配还是简单的malloc, 但是进行了数量统计以及很多系统兼容问题}

    zfree函数

    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
    }
    
    #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)
    

    实现于zmalloc是类似的

    atomicIncr函数

    顾名思义, 很简单就可以猜出是进行原子性加减的函数

    .....
    #define atomicIncr(var,count) __atomic_add_fetch(&var,(count),__ATOMIC_RELAXED)
    
    .....
    #define atomicIncr(var,count) __sync_add_and_fetch(&var,(count))
    
    .....
    #define atomicIncr(var,count) do { \
        pthread_mutex_lock(&var ## _mutex); \
        var += (count); \
        pthread_mutex_unlock(&var ## _mutex); \
    } while(0)
    

      __sync_add_and_fetch是gcc编译器提供的原子性操作,第一个没了解过;如果编译器或者系统未提供原子性操作,即使用锁来实现

    相关文章

      网友评论

          本文标题:Redis zmalloc模块

          本文链接:https://www.haomeiwen.com/subject/imfbwktx.html