redis代码结构之一mem,bio

本文深入解析Redis中的内存管理机制,包括内存分配、释放等基础功能,并介绍了Redis如何利用tcmalloc和jemalloc实现高效内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文章主要记录本人在看redis源码的一些理解和想法。因为功力有限,肯定会出现问题,所以,希望高手给出指正。

第一篇就是内存相关的介绍。因为我喜欢先看一些组件的东西,再看整体的流程。先上一下代码吧

头文件

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //主要提供内存分配和释放的基础功能  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void *zmalloc(size_t size);//主要提供内存分配和释放的基础功能  
  2. void *zcalloc(size_t size);  
  3. void *zrealloc(void *ptr, size_t size);  
  4. void zfree(void *ptr);  
  5. char *zstrdup(const char *s);  
  6. size_t zmalloc_used_memory(void);  
  7. void zmalloc_enable_thread_safeness(void);  
  8. void zmalloc_set_oom_handler(void (*oom_handler)(size_t));  
  9. float zmalloc_get_fragmentation_ratio(void);  
  10. size_t zmalloc_get_rss(void);  
  11. size_t zmalloc_get_private_dirty(void);  
  12. void zlibc_free(void *ptr);  
  13.   
  14. #ifndef HAVE_MALLOC_SIZE  
  15. size_t zmalloc_size(void *ptr);  
  16. #endif  

0.前言

在这块代码我们可以看到HAVE_ATOMIC 宏定义,有什么作用呢,

该文件主要提供了tcmalloc 和jemalloc内存的管理。

tcmalloc是google perftool的一部分,与一般的内存池不同,它直接与os打交道,内存闲置时os会进行回收(stl内存池就不回收),同时使用TLS(Thread local storage)管理内存池,避免一个线程内分配内存都要同步。

jemalloc与tcmalloc相似,作者Jason Evans是Free BSD开发人员,性能与使用率与tcmalloc不相伯仲。tcmalloc更方便与google perftool集成,进行性能评测。


zmalloc主要是 提供了对malloc函数的封装,如果是glibc的malloc函数,那么分配的内存是长度+要分配的的内存,然后将头部放入大小

1.申请内存

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void *zmalloc(size_t size) {  
  2.     void *ptr = malloc(size+PREFIX_SIZE);  
  3.   
  4.     if (!ptr) zmalloc_oom_handler(size);  
  5. #ifdef HAVE_MALLOC_SIZE  
  6.     update_zmalloc_stat_alloc(zmalloc_size(ptr));  
  7.     return ptr;  
  8. #else  
  9.     *((size_t*)ptr) = size;  
  10.     update_zmalloc_stat_alloc(size+PREFIX_SIZE);  
  11.     return (char*)ptr+PREFIX_SIZE;  
  12. #endif  
  13. }  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. update_zmalloc_stat_alloc(zmalloc_size(ptr));是先将自己内存对齐,如果long是4位就对齐到4的整数倍。然后将内存的大小记录下来到一个全局变量中  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 如下代码  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #define update_zmalloc_stat_alloc(__n) do { \  
  2.     size_t _n = (__n); \  
  3.     if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \  
  4.     if (zmalloc_thread_safe) { \  
  5.         update_zmalloc_stat_add(_n); \  
  6.     } else { \  
  7.         used_memory += _n; \  
  8.     } \  
  9. while(0)  
内存对其有很多种方式,他这种也是很有意思。使用long就可以不管是64机器还是32位机器了。如果是在多线程情况下是使用了互斥锁。

如果没定义宏HAVE_MALLOC_SIZE,就在内存的前边四个字节存储器大小。最后返回内存的起始地址。

同理
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void *zcalloc(size_t size)  
该方法封装了calloc 函数功能。

2.重新申请内存

代码如下
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void *zrealloc(void *ptr, size_t size) {  
  2. #ifndef HAVE_MALLOC_SIZE  
  3.     void *realptr;  
  4. #endif  
  5.     size_t oldsize;  
  6.     void *newptr;  
  7.   
  8.     if (ptr == NULL) return zmalloc(size);  
  9. #ifdef HAVE_MALLOC_SIZE  
  10.     oldsize = zmalloc_size(ptr);  
  11.     newptr = realloc(ptr,size);  
  12.     if (!newptr) zmalloc_oom_handler(size);  
  13.   
  14.     update_zmalloc_stat_free(oldsize);  
  15.     update_zmalloc_stat_alloc(zmalloc_size(newptr));  
  16.     return newptr;  
  17. #else  
  18.     realptr = (char*)ptr-PREFIX_SIZE;  
  19.     oldsize = *((size_t*)realptr);  
  20.     newptr = realloc(realptr,size+PREFIX_SIZE);  
  21.     if (!newptr) zmalloc_oom_handler(size);  
  22.   
  23.     *((size_t*)newptr) = size;  
  24.     update_zmalloc_stat_free(oldsize);  
  25.     update_zmalloc_stat_alloc(size);  
  26.     return (char*)newptr+PREFIX_SIZE;  
  27. #endif  
  28. }  

该方法就是对指定的一段内存重新申请指定大小的内存。地址没变化。


3.释放内存

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void zfree(void *ptr) {  
  2. #ifndef HAVE_MALLOC_SIZE  
  3.     void *realptr;  
  4.     size_t oldsize;  
  5. #endif  
  6.   
  7.     if (ptr == NULL) return;  
  8. #ifdef HAVE_MALLOC_SIZE  
  9.     update_zmalloc_stat_free(zmalloc_size(ptr));  
  10.     free(ptr);  
  11. #else  
  12.     realptr = (char*)ptr-PREFIX_SIZE;  
  13.     oldsize = *((size_t*)realptr);  
  14.     update_zmalloc_stat_free(oldsize+PREFIX_SIZE);  
  15.     free(realptr);  
  16. #endif  
  17. }  

4.拷贝内存,封装了memcpy函数
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. char *zstrdup(const char *s) {  
  2.     size_t l = strlen(s)+1;  
  3.     char *p = zmalloc(l);  
  4.   
  5.     memcpy(p,s,l);  
  6.     return p;  
  7. }  

5获取RSS 物理内存值
通过查看进程的/proc/pid/stat 文件的第23行。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. size_t zmalloc_get_rss(void) {  
  2.     int page = sysconf(_SC_PAGESIZE);  
  3.     size_t rss;  
  4.     char buf[4096];  
  5.     char filename[256];  
  6.     int fd, count;  
  7.     char *p, *x;  
  8.   
  9.     snprintf(filename,256,"/proc/%d/stat",getpid());  
  10.     if ((fd = open(filename,O_RDONLY)) == -1) return 0;  
  11.     if (read(fd,buf,4096) <= 0) {  
  12.         close(fd);  
  13.         return 0;  
  14.     }  
  15.     close(fd);  
  16.   
  17.     p = buf;  
  18.     count = 23; /* RSS is the 24th field in /proc/<pid>/stat */  
  19.     while(p && count--) {  
  20.         p = strchr(p,' ');  
  21.         if (p) p++;  
  22.     }  
  23.     if (!p) return 0;  
  24.     x = strchr(p,' ');  
  25.     if (!x) return 0;  
  26.     *x = '\0';  
  27.   
  28.     rss = strtoll(p,NULL,10);  
  29.     rss *= page;  
  30.     return rss;  
  31. }  

6.内存使用率

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /* Fragmentation = RSS / allocated-bytes */  
  2. float zmalloc_get_fragmentation_ratio(void) {  
  3.     return (float)zmalloc_get_rss()/zmalloc_used_memory();  
  4. }  

7.多线程下的原子增加


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifdef HAVE_ATOMIC  
  2. #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))  
  3. #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))  
  4. #else  
  5. #define update_zmalloc_stat_add(__n) do { \  
  6.     pthread_mutex_lock(&used_memory_mutex); \  
  7.     used_memory += (__n); \  
  8.     pthread_mutex_unlock(&used_memory_mutex); \  
  9. while(0)  
  10.   
  11. #define update_zmalloc_stat_sub(__n) do { \  
  12.     pthread_mutex_lock(&used_memory_mutex); \  
  13.     used_memory -= (__n); \  
  14.     pthread_mutex_unlock(&used_memory_mutex); \  
  15. while(0)  
  16.   
  17. #endif  


redis这块内存使用谷歌和jemalloc 进行的内存管理是非常高效的。

对外提供的接口也比较简洁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值