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

第一篇就是内存相关的介绍。由于我喜欢先看一些组件的东西,再看总体的流程。

先上一下代码吧

头文件

//主要提供内存分配和释放的基础功能
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(void);
size_t zmalloc_get_rss(void);
size_t zmalloc_get_private_dirty(void);
void zlibc_free(void *ptr); #ifndef HAVE_MALLOC_SIZE
size_t zmalloc_size(void *ptr);
#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.申请内存

void *zmalloc(size_t size) {
void *ptr = malloc(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
}
 update_zmalloc_stat_alloc(zmalloc_size(ptr));是先将自己内存对齐,假设long是4位就对齐到4的整数倍。然后将内存的大小记录下来到一个全局变量中
例如以下代码
#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)
内存对其有非常多种方式,他这样的也是非常有意思。

使用long就能够无论是64机器还是32位机器了。假设是在多线程情况下是使用了相互排斥锁。


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

同理
void *zcalloc(size_t size)

该方法封装了calloc 函数功能。


2.又一次申请内存

代码例如以下
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
}

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



3.释放内存

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
}

4.拷贝内存,封装了memcpy函数

char *zstrdup(const char *s) {
size_t l = strlen(s)+1;
char *p = zmalloc(l); memcpy(p,s,l);
return p;
}

5获取RSS 物理内存值

通过查看进程的/proc/pid/stat 文件的第23行。

size_t zmalloc_get_rss(void) {
int page = sysconf(_SC_PAGESIZE);
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 = '\0'; rss = strtoll(p,NULL,10);
rss *= page;
return rss;
}

6.内存使用率


/* Fragmentation = RSS / allocated-bytes */
float zmalloc_get_fragmentation_ratio(void) {
return (float)zmalloc_get_rss()/zmalloc_used_memory();
}

7.多线程下的原子添加


#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

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

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

值得学习。



很多其它文章。欢迎关注:




redis源代码解读之内存管理————zmalloc文件的更多相关文章

  1. redis 源代码分析(一) 内存管理

    一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...

  2. redis源码笔记-内存管理zmalloc.c

    redis的内存分配主要就是对malloc和free进行了一层简单的封装.具体的实现在zmalloc.h和zmalloc.c中.本文将对redis的内存管理相关几个比较重要的函数做逐一的介绍 参考: ...

  3. cocos2d-x 源代码分析 : Ref (CCObject) 源代码分析 cocos2d-x内存管理策略

    从源代码版本号3.x.转载请注明 cocos2d-x 总的文件夹的源代码分析: http://blog.csdn.net/u011225840/article/details/31743129 1.R ...

  4. redis持久化机制和内存管理

    redis持久化方式有两种:RDB方式和AOF方式 1.RDB方式:内存快照,在指定的时间间隔对数据进行快照存储,支持在客户端直接BGSAVE或者SAVE命令来创建一个内存快照,BGSAVE会fork ...

  5. 解读Python内存管理机制

    转自:http://developer.51cto.com/art/201007/213585.htm 内存管理,对于Python这样的动态语言,是至关重要的一部分,它在很大程度上甚至决定了Pytho ...

  6. arm-linux学习笔记3-linux内存管理与文件操作

    配置好linux系统之后需要vim配置一下,有助于我们的编程,主要的配置如下 在/etc/vim/vimrc文件中 "显示行号 set number "自动缩进 set autoi ...

  7. Magenta源代码笔记(3) —— 内存管理【转】

    转自:http://blog.csdn.net/boymax2/article/details/52550197 版权声明:本文为博主原创文章,未经博主允许不得转载. Magenta内核支持虚拟地址的 ...

  8. MySQL系列:innodb源代码分析之内存管理

    在innodb中实现了自己的内存池系统和内存堆分配系统,在innodb的内存管理系统中,大致分为三个部分:基础的内存块分配管理.内存伙伴分配器和内存堆分配器.innodb定义和实现内存池的主要目的是提 ...

  9. # 深入理解Redis(二)——内存管理的建议与技巧

    引语 随着使用Redis的深入,我们不可避免的需要深入了解优化Redis的内存,本章将重点讲解Redis的内存优化之道,同时推荐大家阅读memory-optimization一文. 想要高效的使用Re ...

随机推荐

  1. hdu3811(状态压缩dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3811 题目大意:给定1~N个数,求出至少满足一个条件的排列总数.M个条件如下:Ai位置的数为Bi 分析 ...

  2. Spring整合Jms学习(三)_MessageConverter介绍

    1.4     消息转换器MessageConverter MessageConverter的作用主要有双方面,一方面它能够把我们的非标准化Message对象转换成我们的目标Message对象,这主要 ...

  3. 深入java并发Lock一

    java有像syncronized这种内置锁,但为什么还须要lock这种外置锁? 性能并非选择syncronized或者lock的原因,jdk6中syncronized的性能已经与lock相差不大. ...

  4. java的url 中国的争论导致了扭曲

    话不多说,,直接粘代码 发件人 UrlParaCode.jsp <%@ page language="java" import="java.util.*" ...

  5. 【译】ASP.NET MVC 5 教程 - 5:使用 SQL 服务器 LocalDB 创建连接字符串

    原文:[译]ASP.NET MVC 5 教程 - 5:使用 SQL 服务器 LocalDB 创建连接字符串 在上一节中,我们创建了MovieDBContext 类来连接数据库.处理Movie 对象和数 ...

  6. 【译】ASP.NET MVC 5 教程 - 1:入门

    原文:[译]ASP.NET MVC 5 教程 - 1:入门 本教程将教你使用Visual Studio 2013 预览版构建 ASP.NET MVC 5 Web 应用程序 的基础知识.本主题还附带了一 ...

  7. win7系统u盘安装过程

    1.准备好带有启动项的U盘,并把镜像解压到里面去 2.插上u盘,开机长按del键进入bois设置界面 在boot页面 1.boot device priority->1st boot devic ...

  8. Android横屏竖屏设置

    Android横竖屏设置: 方法一:onCreate()中 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // ...

  9. hibernate之关于使用连接表实现多对一关联映射

    [Hibernate]之关于使用连接表实现多对一关联映射 在我们项目使用中採用中间表最多的一般就是多对一,或者是多对多,当然一对一使用中间表也是能够的,可是这样的几率通常少之又少!所以这里重点介绍多对 ...

  10. oracle分区表运行计划

    分区表有非常多优点,以大化小,一小化了,加上并行的使用,在loap中能往往能提高几十倍甚至几百倍的效果. 当然表设计得不好也会适得其反.效果比普通表跟糟糕. 为了更好的使用分区表,这里看一下分区表的运 ...