原创 更新于 时间( 2019-12-11 17:31:11) ( 103) 次浏览 标签 :
导读

Redis源码4.0阅读日记 (1)内存管理 zmalloc ...

开篇先来看看 ——内存管理 分为内存分配,释放 和 统计 Zmalloc.c Zmalloc.h

/* zmalloc - total amount of allocated memory aware version of malloc()
 ...
 */

<span><span>#include <stdio.h>
</span></span>
<span><span>#include <stdlib.h>
</span></span>

<span>// 原生libc free() 的封装
</span>
/* 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. */
void zlibc_free(void *ptr) {
    free(ptr);
}

<span>#include <string.h>
</span>
<span>#include <pthread.h>
</span>
<span>#include "config.h"
</span>
<span>#include "zmalloc.h"
</span>
<span>#include "atomicvar.h"
</span>

HAVE_MALLOC_SIZE & PREFIX_SIZE

首先 HAVE_MALLOC_SIZE 这个宏 ,在 zmalloc.h 中定义了


/* Use tcmalloc's malloc_size() when available.
 * When tcmalloc is used, native OSX malloc_size() may never be used because
 * this expects a different allocation scheme. Therefore, *exclusively* use
 * either tcmalloc or OSX's malloc_size()!
*/

<span>//根据 环境 define HAVE_MALLOC_SIZE    znalloc_size 定义直接使用 平台检测内存块大小的函数
</span>
<span>// 优先使用 tcmalloc
</span>
<span>#if defined(USE_TCMALLOC)
</span>
<span>#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
</span>
<span>#include <google/tcmalloc.h>
</span>
<span>#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
</span>
<span><span><span><span>#define HAVE_MALLOC_SIZE 1
</span></span></span></span>
<span>#define zmalloc_size(p) tc_malloc_size(p)
</span>
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
<span>#error "Newer version of tcmalloc required"
</span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

<span>//jemalloc
</span>
<span>#elif defined(USE_JEMALLOC)
</span>
<span>#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
</span>
<span>#include <jemalloc/jemalloc.h>
</span>
<span>#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
</span>
<span><span><span><span>#define HAVE_MALLOC_SIZE 1
</span></span></span></span>
<span>#define zmalloc_size(p) je_malloc_usable_size(p)
</span>
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
<span>#error "Newer version of jemalloc required"
</span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

<span>// apple
</span>
<span>#elif defined(__APPLE__)
</span>
<span>#include <malloc/malloc.h>
</span>
<span><span><span><span>#define HAVE_MALLOC_SIZE 1
</span></span></span></span>
<span>// p 指向的内存块的大小
</span>
<span>#define zmalloc_size(p) malloc_size(p)
</span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

可以看到,在 jemalloc tcmalloc apple 三种环境下,

<span><span><span><span>#define HAVE_MALLOC_SIZE 1
</span></span></span></span>

回到 zmalloc .c , 根据 HAVE_MALLOC_SIZE 这个宏,来 define PREFIX_SIZE 额外申请的内存空间大小。如果 HAVE_MALLOC_SIZE 存在,那么 PREFIX_SIZE = 0 。如果是在 _sun 或 linux 环境下,PREFIX_SIZE 分别为 sizeof(long long) 和 sizeof(size_t) 长度,需要额外的定长空间存储。

<span><span><span><span><span>#ifdef HAVE_MALLOC_SIZE
</span></span></span></span></span>
<span>#define PREFIX_SIZE (0)
</span>
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
<span>#if defined(__sun) || defined(__sparc) || defined(__sparc__)
</span>
<span>#define PREFIX_SIZE (sizeof(long long))
</span>
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
<span>//linux
</span>
<span>#define PREFIX_SIZE (sizeof(size_t))
</span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

zmalloc

zmalloc 用于 分配 size 大小的内存空间。 SIZE+PREFIX_SIZE 是分配的实际空间大小 用于记录本次申请分配内存空间大小,由上文可知 PREFIX_SIZE linux/sun 环境下需要额外空间

void *zmalloc(size_t size) {
    void *ptr = malloc(size+PREFIX_SIZE);
<span>//如果 malloc(size+PREFIX_SIZE) 调用失败,空ptr指针,就会调用 zmalloc_oom_handler 函数打印异常,终止函数
</span>
    if (!ptr) zmalloc_oom_handler(size);
<span>// zmalloc.h 45 Line
</span>
<span><span><span><span><span>#ifdef HAVE_MALLOC_SIZE
</span></span></span></span></span>
    update_zmalloc_stat_alloc(zmalloc_size(ptr));
    <span>//返回指针指向的内存块地址
</span>
    return ptr;
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    *((size_t*)ptr) = size;
    update_zmalloc_stat_alloc(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
}

zmalloc 调用 malloc 失败之后, zmalloc_oom_handler 函数打印异常,实际调用的是 zmalloc_default_oom

static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;


static void zmalloc_default_oom(size_t size) {
    <span>// oom 异常
</span>
    fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
        size);
    <span>//清除缓冲区
</span>
    fflush(stderr);
    <span>//产生异常程序终止
</span>
    abort();
}

若分配成功,则分配内存块,更新已分配的大小。

<span>// 分配内存的时候更新已分配大小
</span>
<span>#define update_zmalloc_stat_alloc(__n) do { \
</span>
    size_t _n = (__n); \
    <span>// if(_n&7) _n += 8-(_n&7); 判断分配的内存空间大小是不是8的倍数
</span>
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
    atomicIncr(used_memory,__n); \
} while(0)

<span>// 释放内存的时候删除对应的记录
</span>
<span>#define update_zmalloc_stat_free(__n) do { \
</span>
    size_t _n = (__n); \
    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
    atomicDecr(used_memory,__n); \
} while(0)

static size_t used_memory = 0;

zrealloc 重新分配内存

根据 HAVE_MALLOC_SIZE 来设定不同的 old_size realptr ,原因还是由于上面的 PREFIX_SIZE 的不同长度。

void *zrealloc(void *ptr, size_t size) {
<span>// 由 48行 ,如果没有定义HAVE_MALLOC_SIZE,就说明PREFIX_SIZE宏定义不为0,那么ptr并不是该段内存真正的开始地址
</span>
<span><span>#ifndef HAVE_MALLOC_SIZE
</span></span>
    void *realptr;
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
    size_t oldsize;
    void *newptr;

    if (ptr == NULL) return zmalloc(size);
<span><span><span><span><span>#ifdef HAVE_MALLOC_SIZE
</span></span></span></span></span>
    oldsize = zmalloc_size(ptr);
    <span>// 在定义了HAVE_MALLOC_SIZE下; 根据 ptr 直接和  size 进行内存重新分配,没有异常,释放原来的,更新
</span>
    newptr = realloc(ptr,size);
    if (!newptr) zmalloc_oom_handler(size);

    update_zmalloc_stat_free(oldsize);
    update_zmalloc_stat_alloc(zmalloc_size(newptr));
    return newptr;
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    <span>//需要考虑 prefix_size
</span>
    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;
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
}

内存申请函数 zcalloc

void *zcalloc(size_t size) {
    void *ptr = calloc(1, size+PREFIX_SIZE);

    if (!ptr) zmalloc_oom_handler(size);
<span><span><span><span><span>#ifdef HAVE_MALLOC_SIZE
</span></span></span></span></span>
    update_zmalloc_stat_alloc(zmalloc_size(ptr));
    return ptr;
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    *((size_t*)ptr) = size;
    update_zmalloc_stat_alloc(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
}

malloc、calloc、realloc

三者都是分配内存,都是stdlib.h库里的函数 malloc申请后空间的值是随机的,并没有进行初始化 而calloc却在申请后,对空间逐一进行初始化,并设置值为0 realloc 用于对动态内存进行扩容

zfree

内存回收,类似

<span>// 内存回收
</span>
void zfree(void *ptr) {
<span><span>#ifndef HAVE_MALLOC_SIZE
</span></span>
    void *realptr;
    size_t oldsize;
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

    if (ptr == NULL) return;
<span><span><span><span><span>#ifdef HAVE_MALLOC_SIZE
</span></span></span></span></span>
    update_zmalloc_stat_free(zmalloc_size(ptr));
    free(ptr);
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    realptr = (char*)ptr-PREFIX_SIZE;
    oldsize = *((size_t*)realptr);
    update_zmalloc_stat_free(oldsize+PREFIX_SIZE);<span>// 更新use_memory函数。更新已使用内存大小
</span>
    free(realptr);
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
}

zstrdup

复制字符串

<span>//复制字符串
</span>
char *zstrdup(const char *s) {
    size_t l = strlen(s)+1;
    char *p = zmalloc(l);
    <span>//从 s 拷贝 l 个字节 到 p 中
</span>
    memcpy(p,s,l);
    return p;
}

zmalloc_used_memory

获取当前使用的内存总量

<span>// 获取当前使用的内存总量
</span>
size_t zmalloc_used_memory(void) {
    size_t um;
    atomicGet(used_memory,um);
    return um;
}

RSS获取 函数 zmalloc_get_rss

linux rss读取

关于 redis 中的 获取 rss 函数 zmalloc_get_rss ,先看下 Rss linux 下的获取和计算方式,这里介绍一下: 通过 proc/pid/stat 文件解析 RSS 查看一个进行占用的内存页大小

ps -ef |grep redis 
root      9932     1  0 Nov22 ?        00:16:06 ./redis-server 127.0.0.1:6379

cat /proc/9932/stat
9932 (redis-server) S 1 9932 9932 0 -1 4202816 2355 4248 55 3 36587 60102 1 1 20 0 4 0 57700053 150904832 232 18446744073709551615 4194304 5501852 140730684086608 140730684086144 139624267243107 0 0 4097 17610 18446744073709551615 0 0 17 0 0 0 202 0 0 7601536 7622193 39215104 140730684094285 140730684094314 140730684094314 140730684096489 0

第1个参数pid :进程ID 9932 第2个参数pid :comm: task_struct结构体的进程名 (redis-server) 第3个参数pid :state: 进程状态, 此处为 S 第4个参数pid :ppid: 父进程ID (父进程是指通过fork方式,通过clone并非父进程) 1 ... 第20个参数 - num_threads: 线程个数, 此处等于 4 第24个参数 rss: 进程独占内存+共享库,单位pages,此处等于 232

新增了一批 redis 数据后,rss内存页 由 232 -> 1274


[root@budssitapp54 9932]<span># cat stat
</span>
9932 (redis-server) S 1 9932 9932 0 -1 4202816 4112 5278 111 3 37005 60876 6 2 20 0 4 0 57700053 153001984 ` 1274 `
...

<span># linxu 单页的大小(bytes) 可以通过 getconf PAGESIZE 来获取
</span>
[root@budssitapp54 ~]<span># getconf PAGESIZE
</span>
`4096`

系统分页大小为 4096 byte 字节

所以 rss 占用为 4096 * 1274 ~= 4.97 mb

好了,了解了 linux 中 rss 的内存页占用和计算方法,回到redis 源码,看看redis 的处理。

redis rss 获取

如果是 linux / apple 平台,可以通过内置文件获取,比如上面说的 /proc/pid/stat/ ,这样慢,但是准确。 否则就用 RedisEstimateRSS 获取所有已分配的内存来计算,这样快但是不精确。

/* Get the RSS information in an OS-specific way.
 * 操作系统方式获得 rss (Resident Set Size )常驻内存集合大小 此处为获得redis进程在RAM中占用的内存
 * zmalloc_get_rss 不那么快 内存繁忙的时候不会调用
 * 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.
 * RedisEstimateRSS 更快,但不精确
 * 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. */
 
<span>//这个宏在 config.h 的 53 行定义
</span>

<span>#if defined(HAVE_PROC_STAT)
</span>
<span><span>#include <unistd.h>
</span></span>
<span><span>#include <sys/types.h>
</span></span>
<span>#include <sys/stat.h>
</span>
<span>#include <fcntl.h>
</span>

<span>// 获得 rss
</span>
size_t zmalloc_get_rss(void) {
    <span>//page的大小 byte
</span>
    int page = sysconf(_SC_PAGESIZE);
    size_t rss;
    char buf[4096];
    char filename[256];
    int fd, count;
    char *p, *x;

    <span>//读取当前进程pid的stat内容存储在filename中 256位
</span>
    snprintf(filename,256,"/proc/%d/stat",getpid());
    <span>// open系统调用打开 返回int类型的 文件描述符 如果失败 返回0
</span>
    if ((fd = open(filename,O_RDONLY)) == -1) return 0;
    <span>//从fd文件描述符读取数据存储在buf缓冲区,4096字节,返回字节数,失败-1 返回0
</span>
    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--) {
        <span>//存放 遇到' '之后 p 剩下的字节  剩下rss值
</span>
        p = strchr(p,' ');
        if (p) p++;
    }
    if (!p) return 0;
    x = strchr(p,' ');
    if (!x) return 0;
    *x = '\0';

    <span>// p string 转换为10进制
</span>
    rss = strtoll(p,NULL,10);
    rss *= page;
    return rss;
}

<span>//同 config.h Apple环境
</span>
<span>#elif defined(HAVE_TASKINFO)
</span>
<span><span>#include <unistd.h>
</span></span>
<span><span>#include <stdio.h>
</span></span>
<span><span>#include <stdlib.h>
</span></span>
<span><span>#include <sys/types.h>
</span></span>
<span>#include <sys/sysctl.h>
</span>
<span>#include <mach/task.h>
</span>
<span>#include <mach/mach_init.h>
</span>

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;
}
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
size_t zmalloc_get_rss(void) {
    <span>// 如果我们不能从系统途径获得rss ,就返回zmalloc 的总内存使用估算值
</span>
    /* 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();
}
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

zmalloc_get_smap_bytes_by_field

获取 smaps 文件中的值 zmalloc_get_smap_bytes_by_field

/* 同上,获取 smaps 文件中的值
 * 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.
 *
 * If a pid is specified, the information is extracted for such a pid,
 * otherwise if pid is -1 the information is reported is about the
 * current process.
 *
 * Example: zmalloc_get_smap_bytes_by_field("Rss:",-1);
 * 同定义config.h 55L
 */
<span>#if defined(HAVE_PROC_SMAPS)
</span>
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
    char line[1024];
    size_t bytes = 0;
    int flen = strlen(field);
    FILE *fp;

    if (pid == -1) {
        fp = fopen("/proc/self/smaps","r");
    } else {
        char filename[128];
        snprintf(filename,sizeof(filename),"/proc/%ld/smaps",pid);
        fp = fopen(filename,"r");
    }

    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 = '\0';
                bytes += strtol(line+flen,NULL,10) * 1024;
            }
        }
    }
    fclose(fp);
    return bytes;
}
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid) {
    ((void) field);
    ((void) pid);
    return 0;
}
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

获取 smaps 的 Private_Dirty

size_t zmalloc_get_private_dirty(long pid) {
    return zmalloc_get_smap_bytes_by_field("Private_Dirty:",pid);
}

获取物理内存的字节数 zmalloc_get_memory_size

/* 获取物理内存的字节数
 * Returns the size of physical memory (RAM) in bytes.
 * It looks ugly, but this is the cleanest way to achive cross platform results.
 * Cleaned up from:
 *
 * http:<span>//nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
</span>
 *
 * Note that this function:
 * 1) Was released under the following CC attribution license:
 *    http:<span>//creativecommons.org/licenses/by/3.0/deed.en_US.
</span>
 * 2) Was originally implemented by David Robert Nadeau.
 * 3) Was modified for Redis by Matt Stancliff.
 * 4) This note exists in order to comply with the original license.
 */
size_t zmalloc_get_memory_size(void) {
<span>#if defined(__unix__) || defined(__unix) || defined(unix) || \
</span>
    (defined(__APPLE__) && defined(__MACH__))
<span>#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
</span>
    int mib[2];
    mib[0] = CTL_HW;
<span>#if defined(HW_MEMSIZE)
</span>
    mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
<span>#elif defined(HW_PHYSMEM64)
</span>
    mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
    int64_t size = 0;               /* 64-bit */
    size_t len = sizeof(size);
    if (sysctl( mib, 2, &size, &len, NULL, 0) == 0)
        return (size_t)size;
    return 0L;          /* Failed? */

<span>#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
</span>
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
    return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE);

<span>#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
</span>
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
    int mib[2];
    mib[0] = CTL_HW;
<span>#if defined(HW_REALMEM)
</span>
    mib[1] = HW_REALMEM;        /* FreeBSD. ----------------- */
<span>#elif defined(HW_PYSMEM)
</span>
    mib[1] = HW_PHYSMEM;        /* Others. ------------------ */
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
    unsigned int size = 0;      /* 32-bit */
    size_t len = sizeof(size);
    if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
        return (size_t)size;
    return 0L;          /* Failed? */
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    return 0L;          /* Unknown method to get the data. */
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span>#else
</span></span></span></span></span></span></span></span></span></span></span></span>
    return 0L;          /* Unknown OS. */
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span>#endif
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
}

Redis 的内存管理真的是简洁明了

Leon0204

打杂后端程序猿~

讨论区

发表评论
昵称:
评论:
验证