zoukankan      html  css  js  c++  java
  • Redis源码分析(二十五)--- zmalloc内存分配实现

                时间过的很快,经过快1个月的时间学习,本人对Redis源代码的分析已经超过了一半,上几次的学习,我主要的是对于Redis工具类的代码进行了学习。后面的几天我将会学习Redis代码中的一些封装类的实现,这些封装类在整个Redis系统中都可能普遍用到。比如说我马上要分析的在zmalloc的内存封装的实现。先抛开Redis的内存函数库不说,在纯粹的C语言中,内存分配的函数有malloc,free,relloc这3个函数,熟悉C语言编程的同学一定不会陌生。但是在这里Redis代码的编写者,在Redis系统中对内存的分配又做了一次小小封装。我也只能说是一个小小的封装,核心的调用方法仍是C语言中的这3个函数。先看一下在zmalloc.h头文件中define的一些API:

    void *zmalloc(size_t size); /* 调用zmalloc申请size个大小的空间 */
    void *zcalloc(size_t size); /* 调用系统函数calloc函数申请空间 */
    void *zrealloc(void *ptr, size_t size); /* 原内存重新调整空间为size的大小 */
    void zfree(void *ptr); /* 释放空间方法,并更新used_memory的值 */
    char *zstrdup(const char *s); /* 字符串复制方法 */
    size_t zmalloc_used_memory(void); /* 获取当前已经占用的内存大小 */
    void zmalloc_enable_thread_safeness(void); /* 是否设置线程安全模式 */
    void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); /* 可自定义设置内存溢出的处理方法 */
    float zmalloc_get_fragmentation_ratio(size_t rss); /* 所给大小与已使用内存大小之比 */
    size_t zmalloc_get_rss(void);
    size_t zmalloc_get_private_dirty(void); /* 获取私有的脏数据大小 */
    void zlibc_free(void *ptr);  /* 原始系统free释放方法 */
    
    在这里还要介绍几个概念和变量:

    static size_t used_memory = 0;
    static int zmalloc_thread_safe = 0;
    pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    第一个used_memory,看意思我们也知道这是系统已经使用了多少的内存大小,在全局只维护了这么一个变量的大小,说明作者希望根据此来分析出当前的内存的使用情况,第二个zmalloc_thread_safe,这指的是线程安全模式状态,下面的mutext,就是为此服务端,这个在操作系统中就出现过。据此,我们大概知道了,Redis在代码的malloc等操作的时候,会根据创建的大小,会更新used_memory,并操作的模式会有线程安全和不安去模式的区分。

    /* 在对内存空间做使用的时候,进行了加锁控制 */
    #define update_zmalloc_stat_add(__n) do { 
        pthread_mutex_lock(&used_memory_mutex); 
        used_memory += (__n); 
        pthread_mutex_unlock(&used_memory_mutex); 
    } while(0)
    上面的函数操作就是线程安全模式时候的一个操作,通过锁操作实现对于used_memory的控制,是对这个变量做控制,避免了这个数值出现脏数据的可能。

    /* 调用zmalloc申请size个大小的空间 */
    void *zmalloc(size_t size) {
    	//实际调用的还是malloc函数
        void *ptr = malloc(size+PREFIX_SIZE);
    	
    	//如果申请的结果为null,说明发生了oom,调用oom的处理方法
        if (!ptr) zmalloc_oom_handler(size);
    #ifdef HAVE_MALLOC_SIZE
    	//更新used_memory的大小
        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
    }
    
    zmalloc的具体实现,调用的还是malloc的C语言方法,做了OOM的异常处理,然后更新大小。在update_zmalloc_stat_alloc方法里面:

    /* 申请新的_n大小的内存,分为线程安全,和线程不安全的模式 */
    #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)
    同理zfree()的操作就是上面的反操作,调用free方法,把used_memory的值,做减少操作。在APIL里面还出现了zcalloc方法,下面函数代码中我分析一下这个函数和malloc到底有什么不同呢:

    /* 调用系统函数calloc函数申请空间 */
    void *zcalloc(size_t size) {
    	//calloc与malloc的意思一样,不过参数不一样
    	//void *calloc(size_t numElements,size_t sizeOfElement),;numElements * sizeOfElement才是最终的内存的大小
    	//所在这里就是申请一块大小为size+PREFIX_SIZE的空间
        void *ptr = calloc(1, 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
    }
    
    在这些方法中,作者很人性化的开放了一些API给用户调用,比如说为了效率的提高,可以不开启安全模式啊;

    /* 是否设置线程安全模式 */
    void zmalloc_enable_thread_safeness(void) {
        zmalloc_thread_safe = 1;
    }
    
    或者自定义一个更合理的内存溢出的处理函数,更满足系统的需要:

    /* 可自定义设置内存溢出的处理方法 */
    void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
        zmalloc_oom_handler = oom_handler;
    }
  • 相关阅读:
    B.Icebound and Sequence
    Educational Codeforces Round 65 (Rated for Div. 2) D. Bicolored RBS
    Educational Codeforces Round 65 (Rated for Div. 2) C. News Distribution
    Educational Codeforces Round 65 (Rated for Div. 2) B. Lost Numbers
    Educational Codeforces Round 65 (Rated for Div. 2) A. Telephone Number
    Codeforces Round #561 (Div. 2) C. A Tale of Two Lands
    Codeforces Round #561 (Div. 2) B. All the Vowels Please
    Codeforces Round #561 (Div. 2) A. Silent Classroom
    HDU-2119-Matrix(最大匹配)
    读书的感想!
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184215.html
Copyright © 2011-2022 走看看