redis中的memory管理

redis 中申请memory的实现在zmalloc.c/h 中。仔细阅读这两个文件可以返现redis 对memory的申请和释放方式都是在glibc
中提供的malloc/free 的封装.
我们以申请memory函数中的zmalloc 为例
void *zmalloc(size_t size) {
	//调用malloc 来申请内存,注意这里申请的size ,会在形参size的基础上加上PREFIX_SIZE
    void *ptr = malloc(size+PREFIX_SIZE);
	//ptr为null,则表示申请失败,调用自定义的oom函数处理
    if (!ptr) zmalloc_oom_handler(size);
	#如果定义了HAVE_MALLOC_SIZE ,更新已经通过zmalloc 申请的size后就返回了
#ifdef HAVE_MALLOC_SIZE
    update_zmalloc_stat_alloc(zmalloc_size(ptr));
    return ptr;
#else
     #否则的话,就在ptr 保存好形参的size,然后在prt的基础上偏移PREFIX_SIZE的地址返回给用户
	 #因为在ptr这个地址我们保存原始形参的size
    *((size_t*)ptr) = size;
    update_zmalloc_stat_alloc(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
#endif
}
其中PREFIX_SIZE的定义如下:
#ifdef HAVE_MALLOC_SIZE
#define PREFIX_SIZE (0)
#else
#if defined(__sun) || defined(__sparc) || defined(__sparc__)
#define PREFIX_SIZE (sizeof(long long))
#else
#define PREFIX_SIZE (sizeof(size_t))
#endif
#endif
那我们看看
#define update_zmalloc_stat_alloc(__n) do { \
    size_t _n = (__n); \
	#这个if条件成立的话,说明形参n不是sizeof(long)对齐的,这里就会对齐
    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)
假定zmalloc_thread_safe 返回false的话,我们通过zmalloc申请的size就会保存在used_memorg 这个全局变量中
假如zmalloc_thread_safe 等于true的话,可以看到是通过原子操作来更新used_memory的值
#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

这里需要注意吗,如果编译器提供原子操作,则调用__sync_add_and_fetch 来加上size,否则通过pthread_mutex_lock来加锁保护
zmalloc 只是分配内存函数中的一个,其他还有
void *zmalloc(size_t size);
void *zcalloc(size_t size);
void *zrealloc(void *ptr, size_t size);
但是实现基本类似
既然zmalloc 分了两种case,那free函数应该也分两种case
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
}
结构和zmalloc的刚好相反.

前面我们知道通过zmalloc申请的memory的总size 是保存在used_memory这个全局变量中,但是我们却不能
直接读取这个值,而是要通过下面这个函数获取
size_t zmalloc_used_memory(void) {
    size_t um;
	#是否线程安全
    if (zmalloc_thread_safe) {
#ifdef HAVE_ATOMIC
		#编译器支持原子读取
        um = __sync_add_and_fetch(&used_memory, 0);
#else
		#编译器不支持,则通过锁保护防止在读这个值的同时对这个值写
        pthread_mutex_lock(&used_memory_mutex);
        um = used_memory;
        pthread_mutex_unlock(&used_memory_mutex);
#endif
    }
    else {
	#非线程安全的话,直接返回这个值.
        um = used_memory;
    }

    return um;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值