zoukankan      html  css  js  c++  java
  • redis内存管理代码的目光

    zmalloc.h

    /* zmalloc - total amount of allocated memory aware version of malloc()
     *
     * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *   * Redistributions of source code must retain the above copyright notice,
     *     this list of conditions and the following disclaimer.
     *   * Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *   * Neither the name of Redis nor the names of its contributors may be used
     *     to endorse or promote products derived from this software without
     *     specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     * POSSIBILITY OF SUCH DAMAGE.
     */
    
    #ifndef __ZMALLOC_H
    #define __ZMALLOC_H
    
    /* Double expansion needed for stringification of macro values. */
    #define __xstr(s) __str(s)
    #define __str(s) #s
    
    //TCMALLOC内存分配器
    #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			//TCMALLOC内置获取分配内存空间大小的函数
    #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
    
    //使用默认libc分配器
    #ifndef ZMALLOC_LIB
    #define ZMALLOC_LIB "libc"
    #endif
    
    void *zmalloc(size_t size);
    void *zcalloc(size_t size);
    void *zrealloc(void *ptr, size_t size);
    void zfree(void *ptr);
    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);
    size_t zmalloc_get_smap_bytes_by_field(char *field);
    void zlibc_free(void *ptr);
    
    #ifndef HAVE_MALLOC_SIZE
    size_t zmalloc_size(void *ptr);
    #endif
    
    #endif /* __ZMALLOC_H */
    

    zmalloc.c

    /* zmalloc - total amount of allocated memory aware version of malloc()
     *
     * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *   * Redistributions of source code must retain the above copyright notice,
     *     this list of conditions and the following disclaimer.
     *   * Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *   * Neither the name of Redis nor the names of its contributors may be used
     *     to endorse or promote products derived from this software without
     *     specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     * POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    /* This function provide us access to the original libc free(). This is useful
     * for instance to free results obtained by backtrace_symbols(). We need
     * to define this function before including zmalloc.h that may shadow the
     * free implementation if we use jemalloc or another non standard allocator. */
    
     //保留了libc的free()接口。用于释放backtrace_symbols()获取的结果
    void zlibc_free(void *ptr) {
        free(ptr);
    }
    
    #include <string.h>
    #include <pthread.h>
    #include "config.h"
    #include "zmalloc.h"
    
    #ifdef HAVE_MALLOC_SIZE //tc_malloc,je_malloc,Mac平台
    #define PREFIX_SIZE (0)
    #else
    /*其它平台内存分配
    **内存模型:data_size(PREFIX_SIZE)+data
    **前面PREFIX_SIZE字节存储申请空间大小。后面空间为申请的内存
    */
    #if defined(__sun) || defined(__sparc) || defined(__sparc__)
    #define PREFIX_SIZE (sizeof(long long))
    #else                   //linux
    #define PREFIX_SIZE (sizeof(size_t))
    #endif
    #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
    
    //原子操作改动总共使用内存
    #if defined(__ATOMIC_RELAXED)
    #define update_zmalloc_stat_add(__n) __atomic_add_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
    #define update_zmalloc_stat_sub(__n) __atomic_sub_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
    #elif defined(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
    
    //__n是分配的内存字节。更新used_memory的值,注意long型对齐
    #define update_zmalloc_stat_alloc(__n) do { 
        size_t _n = (__n); 
        if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1));     //分配字节不到long型的整数倍添加至整数倍
        if (zmalloc_thread_safe) {     //线程安全模式
            update_zmalloc_stat_add(_n); 
        } else {                       //非线程安全模式
            used_memory += _n; 
        } 
    } while(0)
    
    //__n是释放的内存字节,更新used_memory的值,注意long型对齐
    #define update_zmalloc_stat_free(__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_sub(_n); 
        } else { 
            used_memory -= _n; 
        } 
    } while(0)
    
    
    static size_t used_memory = 0;          //初始时总共使用内存空间为0
    static int zmalloc_thread_safe = 0;     //默认不启动线程安全模式
    pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;  //定义并初始化一个相互排斥量
    
    //内存不足默认处理函数
    static void zmalloc_default_oom(size_t size) {
        fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes
    ",
            size);
        fflush(stderr);
        abort();
    }
    
    //内存不足处理函数指针。初始为默认函数
    static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;
    
    //malloc实现内存申请函数
    void *zmalloc(size_t size) {
        void *ptr = malloc(size+PREFIX_SIZE);
    
        if (!ptr) zmalloc_oom_handler(size);    //申请失败调用内存不足处理函数,终止程序
    #ifdef HAVE_MALLOC_SIZE                     //tc_malloc,je_malloc,Mac平台
        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
    }
    
    //calloc实现内存释放函数
    void *zcalloc(size_t 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
    }
    
    void *zrealloc(void *ptr, size_t size) {
    #ifndef HAVE_MALLOC_SIZE
        void *realptr;
    #endif
        size_t oldsize;
        void *newptr;
    
        if (ptr == NULL) return zmalloc(size);
    #ifdef HAVE_MALLOC_SIZE
        oldsize = zmalloc_size(ptr);
        newptr = realloc(ptr,size);
        if (!newptr) zmalloc_oom_handler(size);
    
        update_zmalloc_stat_free(oldsize);
        update_zmalloc_stat_alloc(zmalloc_size(newptr));
        return newptr;
    #else
        realptr = (char*)ptr-PREFIX_SIZE;
        oldsize = *((size_t*)realptr);
        newptr = realloc(realptr,size+PREFIX_SIZE);
        if (!newptr) zmalloc_oom_handler(size);
    
        *((size_t*)newptr) = size;
        update_zmalloc_stat_free(oldsize);
        update_zmalloc_stat_alloc(size);
        return (char*)newptr+PREFIX_SIZE;
    #endif
    }
    
    /* Provide zmalloc_size() for systems where this function is not provided by
     * malloc itself, given that in that case we store a header with this
     * information as the first bytes of every allocation. */
    #ifndef HAVE_MALLOC_SIZE
    size_t zmalloc_size(void *ptr) {
        void *realptr = (char*)ptr-PREFIX_SIZE;
        size_t size = *((size_t*)realptr);
        /* Assume at least that all the allocations are padded at sizeof(long) by
         * the underlying allocator. */
        //如果全部分配器分配时均使用long型对齐
        if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));
        return size+PREFIX_SIZE;
    }
    #endif
    
    //释放ptr指向的内存空间
    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
    }
    
    char *zstrdup(const char *s) {
        size_t l = strlen(s)+1;
        char *p = zmalloc(l);
    
        memcpy(p,s,l);
        return p;
    }
    
    //返回总共的使用内存
    size_t zmalloc_used_memory(void) {
        size_t um;
    
        if (zmalloc_thread_safe) {
    #if defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)
            um = update_zmalloc_stat_add(0);
    #else
            pthread_mutex_lock(&used_memory_mutex);
            um = used_memory;
            pthread_mutex_unlock(&used_memory_mutex);
    #endif
        }
        else {
            um = used_memory;
        }
    
        return um;
    }
    
    //设置安全线程模式
    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;
    }
    
    /* Get the RSS information in an OS-specific way.
     *
     * WARNING: the function zmalloc_get_rss() is not designed to be fast
     * and may not be called in the busy loops where Redis tries to release
     * memory expiring or swapping out objects.
     *
     * For this kind of "fast RSS reporting" usages use instead the
     * function RedisEstimateRSS() that is a much faster (and less precise)
     * version of the function. */
    
    #if defined(HAVE_PROC_STAT)
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    //获取当前进程的驻留集大小
    size_t zmalloc_get_rss(void) {
        int page = sysconf(_SC_PAGESIZE);   //获取page大小
        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 = '';
    
        rss = strtoll(p,NULL,10);
        rss *= page;
        return rss;
    }
    #elif defined(HAVE_TASKINFO)
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/sysctl.h>
    #include <mach/task.h>
    #include <mach/mach_init.h>
    
    size_t zmalloc_get_rss(void) {
        task_t task = MACH_PORT_NULL;
        struct task_basic_info t_info;
        mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
    
        if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS)
            return 0;
        task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
    
        return t_info.resident_size;
    }
    #else
    size_t zmalloc_get_rss(void) {
        /* If we can't get the RSS in an OS-specific way for this system just
         * return the memory usage we estimated in zmalloc()..
         *
         * Fragmentation will appear to be always 1 (no fragmentation)
         * of course... */
        return zmalloc_used_memory();
    }
    #endif
    
    /* Fragmentation = RSS / allocated-bytes */
    //计算碎片率
    float zmalloc_get_fragmentation_ratio(size_t rss) {
        return (float)rss/zmalloc_used_memory();
    }
    
    /* Get the sum of the specified field (converted form kb to bytes) in
     * /proc/self/smaps. The field must be specified with trailing ":" as it
     * apperas in the smaps output.
     *
     * Example: zmalloc_get_smap_bytes_by_field("Rss:");
     */
    
    #if defined(HAVE_PROC_SMAPS)
    size_t zmalloc_get_smap_bytes_by_field(char *field) {
        char line[1024];
        size_t bytes = 0;
        FILE *fp = fopen("/proc/self/smaps","r");
        int flen = strlen(field);
    
        if (!fp) return 0;
        while(fgets(line,sizeof(line),fp) != NULL) {
            if (strncmp(line,field,flen) == 0) {
                char *p = strchr(line,'k');
                if (p) {
                    *p = '';
                    bytes += strtol(line+flen,NULL,10) * 1024;
                }
            }
        }
        fclose(fp);
        return bytes;
    }
    #else
    size_t zmalloc_get_smap_bytes_by_field(char *field) {
        ((void) field);
        return 0;
    }
    #endif
    
    //获取Private_Dirty大小,RSS=Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty
    //Shared_Clean:引用大于1,未被改动
    //Shared_Dirty:引用大于1,被改动
    //Private_Clean:引用等于1,未被改动
    //Private_Dirty:引用等于1,被改动
    size_t zmalloc_get_private_dirty(void) {
        return zmalloc_get_smap_bytes_by_field("Private_Dirty:");
    }
    


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    flume,kafka不在一个内网互相打通.md
    尚硅谷Flink2020教程.md
    常用命令.md
    四象限工作效率-事件管理.md
    甘特图目标实施-进度管控.md
    PDCA循环法.md
    SMART大目标拆解小目标.md
    基于内外部竞争环境和竞争条件下的态势分析
    使用Java正则表达式批量提取文本信息
    使用markdown高效编写博客(创建标题)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4801664.html
Copyright © 2011-2022 走看看