1. 程式人生 > >muduo原始碼分析(2) --記憶體分配

muduo原始碼分析(2) --記憶體分配

寫在前面:

​ 這個原始碼是分析libevent-2.0.20-stable, 並非最新版本的libevent,作者並沒有全看原始碼,在這裡會推薦以下參考的一些網站,也歡迎大家在不足的地方提出來進行討論。

什麼都沒包裝的記憶體管理

​ 預設情況下,libevent 使用 C 庫的記憶體管理函式在堆上分配記憶體。通過提供 malloc、realloc和 free 的替代函式,可以讓 libevent 使用其他的記憶體管理器。希望 libevent 使用一個更高效的分配器時;或者希望 libevent 使用一個工具分配器,以便檢查記憶體洩漏時,可能需要這樣做。

//mm-internal.h
void *event_mm_malloc_(size_t sz);
void *event_mm_calloc_(size_t count, size_t size);
char *event_mm_strdup_(const char *s);
void *event_mm_realloc_(void *p, size_t sz);
void event_mm_free_(void *p);
#define mm_malloc(sz) event_mm_malloc_(sz)
#define mm_calloc(count, size) event_mm_calloc_((count), (size))
#define mm_strdup(s) event_mm_strdup_(s)
#define mm_realloc(p, sz) event_mm_realloc_((p), (sz))
#define mm_free(p) event_mm_free_(p)

​ 當我們追溯這些檔案,到event.c中,會看到這些所謂的函式,在沒有自定義的情況下僅僅只是呼叫了C 的記憶體分配API

void *
event_mm_malloc_(size_t sz)
{
    if (_mm_malloc_fn)
        return _mm_malloc_fn(sz);
    else
        return malloc(sz);
}
void *
event_mm_calloc_(size_t count, size_t size)
{
    if (_mm_malloc_fn) {
        size_t sz = count * size;
        void *p = _mm_malloc_fn(sz);
        if (p)
            memset(p, 0, sz);
        return p;
    } else
        return calloc(count, size);
}
​
void *
event_mm_realloc_(void *ptr, size_t sz)
{
    if (_mm_realloc_fn)
        return _mm_realloc_fn(ptr, sz);
    else
        return realloc(ptr, sz);
}
void
event_mm_free_(void *ptr)
{
    if (_mm_free_fn)
        _mm_free_fn(ptr);
    else
        free(ptr);
}

嘗試定義自己的記憶體管理函式

​ 看到上面的實現,一定會有人想問,上面的像_mm_free_fn到底是什麼呢?我們要如何使用它呢?

static void *(*_mm_malloc_fn)(size_t sz) = NULL;
static void *(*_mm_realloc_fn)(void *p, size_t sz) = NULL;
static void (*_mm_free_fn)(void *p) = NULL;

​ 它們其實是event.c中的靜態全域性變數,所以我們僅只能通過下面的函式對其進行操作

void
event_set_mem_functions(void *(*malloc_fn)(size_t sz),
            void *(*realloc_fn)(void *ptr, size_t sz),
            void (*free_fn)(void *ptr))
{
    _mm_malloc_fn = malloc_fn;
    _mm_realloc_fn = realloc_fn;
    _mm_free_fn = free_fn;
}

​ 如果想編譯生成的庫含有上述巨集和實現,就必須在編譯定義_EVENT_DISABLE_MM_REPLACEMENT這個巨集,這個巨集的定義是靠./configure自動生成的event-config,h定義的,若想要取消自定義記憶體函式,可以在編Libevent

加入--disable-malloc-replacement。

不得不提的注意事項

  • 替換記憶體管理函式影響 libevent 隨後的所有分配、調整大小和釋放記憶體操作。所以,必

  • 須保證在呼叫任何其他 libevent 函式之前進行替換。否則,libevent 可能用你的 free 函式釋放用 C 庫的 malloc 分配的記憶體。

  • 你的 malloc 和 realloc 函式返回的記憶體塊應該具有和 C 庫返回的記憶體塊一樣的地址對齊。

  • 你的 realloc 函式應該正確處理 realloc(NULL,sz)(也就是當作 malloc(sz)處理)

  • 你的 realloc 函式應該正確處理 realloc(ptr,0)(也就是當作 free(ptr)處理)

  • 你的 free 函式不必處理 free(NULL)

  • 你的 malloc 函式不必處理 malloc(0)

  • 如果在多個執行緒中使用 libevent,替代的記憶體管理函式需要是執行緒安全的。

  • libevent 將使用這些函式分配返回給你的記憶體。所以,如果要釋放由 libevent 函式分配和返回的記憶體,而你已經替換 malloc 和 realloc 函式,那麼應該使用替代的 free 函式

其實這些條款看似複雜,其實就是一個兩個問題:

​ 1.malloc realloc free要配套,否則加入你在自己申請的記憶體池分配空間,呼叫系統free,然後在下一次使用那塊空間的時候,就會dump core

​ 2.在多執行緒的情況下要求執行緒安全