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.在多執行緒的情況下要求執行緒安全