Redis内存管理的基石zmallc.c源码解读(二)

上一篇博文中,我介绍了zmalloc.c文件中几个常用的函数,接下来给大家介绍一下该文件中的其他函数,其实本文中的很多函数要比上一篇文章中的函数要更有趣的,并且涉及到很多操作系统的知识。前面几个函数比较简单,一笔带过,后面几个是学习的重点。

开胃菜zmalloc_enable_thread_safeness

void zmalloc_enable_thread_safeness(void) {zmalloc_thread_safe = 1;} zmalloc_thread_safe是一个全局静态变量(static int)。它是操作是否是线程安全的标识。1 表示线程安全,0 表示非线程安全。

zmalloc_used_memory

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);#elsepthread_mutex_lock(&used_memory_mutex);um = used_memory;pthread_mutex_unlock(&used_memory_mutex);#endif}else {um = used_memory;}return um;} 该函数要完成的操作就是返回变量used_memory(已用内存)的值,所以它的功能是查询系统当前为Redis分配的内存大小。本身代码量不大,但是涉及到了线程安全模式下的查询操作。实现线程同步用到了互斥锁(mutex)。关于互斥锁的内容在上一篇文章中已经简要介绍过了。总之要记住的是加锁(pthread_mutex_lock)和解锁(pthread_mutex_unlock)。在加了互斥锁之后,就能保证之后的代码同时只能被一个线程所执行。zmalloc_set_oom_handler

void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {zmalloc_oom_handler = oom_handler;} 该函数的功能是给zmalloc_oom_handler赋值。zmalloc_oom_handler是一个函数指针,表示在内存不足(out of memory,缩写oom)的时候所采取的操作,它的类型是void (*) (size_t)。所以zmalloc_set_oom_handler函数的参数也是void (*) (size_t)类型,调用的时候就是传递一个该类型的函数名就可以了。

不过zmalloc_oom_handler在声明的时候初始化了默认值——zmalloc_default_oom()。同样在上一篇博文中也有过介绍。

zmalloc_size

#ifndef HAVE_MALLOC_SIZEsize_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. */if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1));return size+PREFIX_SIZE;}#endif 这段代码和我在上一篇博文中介绍的zfree()函数中的内容颇为相似。大家可以去阅读那一篇博文。这里再概括一下,zmalloc(size)在分配内存的时候会多申请sizeof(size_t)个字节大小的内存【64位系统中是8字节】,即调用malloc(size+8),所以一共申请分配size+8个字节,zmalloc(size)会在已分配内存的首地址开始的8字节中存储size的值,实际上因为内存对齐,malloc(size+8)分配的内存可能会比size+8要多一些,目的是凑成8的倍数,所以实际分配的内存大小是size+8+X【(size+8+X)%8==0 (0<=X<=7)】。然后内存指针会向右偏移8个字节的长度。zfree()就是zmalloc()的一个逆操作,而zmalloc_size()的目的就是计算出size+8+X的总大小。

————————————————————————————————————————————————————–

这个函数是一个条件编译的函数,通过阅读zmalloc.h文件,我们可以得知zmalloc_size()依据不同的平台,具有不同的宏定义,因为在某些平台上提供查询已分配内存实际大小的函数,可以直接#define zmalloc_size(p):

当这三个平台都不存在的时候,就自定义,也就是上面的源码。

————————————————————————————————————————————————————–

大餐zmalloc_get_rss

获取RSS的大小,这个RSS可不是我们在网络上常常看到的RSS,而是指的Resident Set Size,表示当前进程实际所驻留在内存中的空间大小,即不包括被交换(swap)出去的空间。

了解一点操作系统的知识,就会知道我们所申请的内存空间不会全部常驻内存,系统会把其中一部分暂时不用的部分从内存中置换到swap区(装Linux系统的时候我们都知道有一个交换空间)。

该函数大致的操作就是在当前进程的 /proc/<pid>/stat 【<pid>表示当前进程id】文件中进行检索。该文件的第24个字段是RSS的信息,它的单位是pages(内存页的数目)

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;} 函数开头:

int page = sysconf(_SC_PAGESIZE);

通过调用库函数sysconf()【大家可以man sysconf查看详细内容】来查询内存页的大小。

接下来:

绊住的不仅是双脚,还有未来。

Redis内存管理的基石zmallc.c源码解读(二)

相关文章:

你感兴趣的文章:

标签云: