zoukankan      html  css  js  c++  java
  • 深入redis内部--内存管理

    1. Redis内存管理通过在zmalloc.h和zmalloc.c中重写c语言对内存的管理来完成的。

    redis内存管理 c内存管理 原型 作用
    zmalloc malloc void *malloc(unsigned int num_bytes); 分配一块指定大小的内存区域,并返回指向该区域头部的指针,分配失败则返回NULL
    zcalloc calloc void *calloc(unsigned n, unsigned size); 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
    zrealloc realloc oid *realloc(void *mem_address, unsigned int newsize); 先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
    zfree free void free(void *ptr)  释放ptr指向的存储空间。被释放的空间通常被送入可用存储区池,以后可在调用malloc、realloc以及calloc函数来再分配。

    封装就是为了屏蔽底层平台的差异,同时方便自己实现相关的统计函数。

    定义平台之间的差异,主要是tcmalloc(google)、jemalloc(facebook)、苹果平台。

    具体来说就是:

    • 若系统中存在Google的TC_MALLOC库,则使用tc_malloc一族函数代替原本的malloc一族函数。
    • 若系统中存在facebook的JE_MALLOC库,则使用je_malloc一族函数替换原来的malloc一族函数。
    • 若当前系统是Mac系统或者其它系统,则使用<malloc/malloc.h>中的内存分配函数。
    /* Double expansion needed for stringification of macro values. */
    #define __xstr(s) __str(s)
    #define __str(s) #s
    
    #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
    
    #elif defined(USE_JEMALLOC)
    #define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
    #include <jemalloc/jemalloc.h>
    #if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
    #define HAVE_MALLOC_SIZE 1
    #define zmalloc_size(p) je_malloc_usable_size(p)
    #else
    #error "Newer version of jemalloc required"
    #endif
    
    #elif defined(__APPLE__)
    #include <malloc/malloc.h>
    #define HAVE_MALLOC_SIZE 1
    #define zmalloc_size(p) malloc_size(p)
    #endif

    具体如下:

    /* Explicitly override malloc/free etc when using tcmalloc. */
    #if defined(USE_TCMALLOC)
    #define malloc(size) tc_malloc(size)
    #define calloc(count,size) tc_calloc(count,size)
    #define realloc(ptr,size) tc_realloc(ptr,size)
    #define free(ptr) tc_free(ptr)
    #elif defined(USE_JEMALLOC)
    #define malloc(size) je_malloc(size)
    #define calloc(count,size) je_calloc(count,size)
    #define realloc(ptr,size) je_realloc(ptr,size)
    #define free(ptr) je_free(ptr)
    #endif
    
    #ifdef HAVE_ATOMIC
    #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
    #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
    #else
    #define update_zmalloc_stat_add(__n) do { 
        pthread_mutex_lock(&used_memory_mutex); 
        used_memory += (__n); 
        pthread_mutex_unlock(&used_memory_mutex); 
    } while(0)
    
    #define update_zmalloc_stat_sub(__n) do { 
        pthread_mutex_lock(&used_memory_mutex); 
        used_memory -= (__n); 
        pthread_mutex_unlock(&used_memory_mutex); 
    } while(0)
    
    #endif

    说明:

    Both libraries try to de-contention memory acquire by having threads pick the memory from different caches, but they have different strategies:

    
    
    • jemalloc (used by Facebook) maintains a cache per thread
    • tcmalloc (from Google) maintains a pool of caches, and threads develop a "natural" affinity for a cache, but may change
    
    

    This led, once again if I remember correctly, to an important difference in term of thread management.

    
    
    • jemalloc is faster if threads are static, for example using pools
    • tcmalloc is faster when threads are created/destructed

    1.1 zmalloc实现      

    void *zmalloc(size_t size) {
        void *ptr = malloc(size+PREFIX_SIZE);
    
        if (!ptr) zmalloc_oom_handler(size); //如果没有发生内存溢出,则使用的分配方式static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
    #ifdef HAVE_MALLOC_SIZE                  //HAVE_MALLOC_SIZE用来确定系统是否有函数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
    }
    #define update_zmalloc_stat_alloc(__n) do { 
        size_t _n = (__n); 
        if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); 
        if (zmalloc_thread_safe) { 
            update_zmalloc_stat_add(_n); 
        } else { 
            used_memory += _n; 
        } 
    } while(0)
    
    #ifdef HAVE_ATOMIC
    #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
    #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
    #else
    #define update_zmalloc_stat_add(__n) do { 
        pthread_mutex_lock(&used_memory_mutex); 
        used_memory += (__n); 
        pthread_mutex_unlock(&used_memory_mutex); 
    } while(0)
    
    #define update_zmalloc_stat_sub(__n) do { 
        pthread_mutex_lock(&used_memory_mutex); 
        used_memory -= (__n); 
        pthread_mutex_unlock(&used_memory_mutex); 
    } while(0)
    
    #endif

    说明

    int pthread_mutex_lock(pthread_mutex_t *mutex);

    当pthread_mutex_lock()返回时,该互斥锁已被锁定。线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。

    int pthread_mutex_unlock(pthread_mutex_t *mutex);和上面的函数为一对。

    其它函数的实现类似。

  • 相关阅读:
    各类Http请求状态(status)及其含义 速查列表 xmlhttp status
    Microsoft Visual Studio 2010 正式版下载[含旗舰版序列号](中、英文版)
    【分享】开源或免费的ASP.NET web应用列表
    线程间操作无效: 从不是创建控件“Control Name'”的线程访问它问题的解决方案及原理分析
    Asp.Net中多语言的实现
    Oracle 数字与空值的排序问题
    新版微软一站式示例代码库 6月2日更新下载。
    .NET反射机制简介
    Decimal与double类型误差
    用动态菜单增强.NET应用程序
  • 原文地址:https://www.cnblogs.com/davidwang456/p/3504563.html
Copyright © 2011-2022 走看看