redis原始碼解讀之記憶體管理————zmalloc檔案

來源:互聯網
上載者:User

標籤:

本文章主要記錄本人在看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_SIZEsize_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這塊記憶體使用量Google和jemalloc 進行的記憶體管理是很高效的。
對外提供的介面也比較簡潔。
值得學習。



很多其它文章。歡迎關註:



redis原始碼解讀之記憶體管理————zmalloc檔案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.