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;
    }
  • 相关阅读:
    Codeforces Round #481 (Div. 3) D. Almost Arithmetic Progression
    Codeforces Round #481 (Div. 3) G. Petya's Exams
    使用create-react-app 搭建react + ts + antd框架
    callback、promise和async、await的使用方法
    JS数组中Array.of()方法的使用
    react中替换关键字并且高亮显示的方法
    封装 jsonp请求数据的方法
    React的新特性 ---- Hooks ---- 的基本使用
    在canvas中使用其他HTML元素
    React的性能优化
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184213.html
Copyright © 2011-2022 走看看