1. 程式人生 > >Libevent原始碼分析-----記憶體分配

Libevent原始碼分析-----記憶體分配

    Libevent的記憶體分配函式還是比較簡單的,並沒有定義記憶體池之類的東西。如同前一篇部落格那樣,給予Libevent庫的使用者充分的設定權(定製),即可以設定使用者(Libevent庫的使用者)自己的記憶體分配函式。至於怎麼分配,主動權在於使用者。但在設定(定製)的時候要注意一些地方,下面會說到。

        首先,如果要定製自己的記憶體分配函式,就得在一開始配置編譯Libevent庫是,不能加入--disable-malloc-replacement選項。預設情況下,是沒有這個選項的。如果加入了這個選項,那麼將會在生成的event-config.h中,定義_EVENT_DISABLE_MM_REPLACEMENT這個巨集。關於event-config.h檔案,

可以參考博文。下面是Libevent記憶體分配函式的宣告(在mm-internal.h檔案):

//mm-internal.h檔案

#ifndef _EVENT_DISABLE_MM_REPLACEMENT

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)

#else

#define mm_malloc(sz) malloc(sz)

#define mm_calloc(n, sz) calloc((n), (sz))

#define mm_strdup(s) strdup(s)

#define mm_realloc(p, sz) realloc((p), (sz))

#define mm_free(p) free(p)

#endif

        這些記憶體分配函式是給Libevent使用的,而非使用者(從這些介面宣告在mm-internal.h檔案中就可以看到這一點)。Libevent的其他函式要申請記憶體就呼叫mm_malloc之類的巨集定義。如果一開始在配置的時候(event-config.h)就禁止使用者定製自己的記憶體分配函式,那麼就把這些巨集定義為C語言標準記憶體分配函式。

        當然,即使沒有禁止,如果使用者沒有定製自己的記憶體分配函式,最終還是呼叫C語言的標準記憶體分配函式。這一點在event_mm_xxxx這些函式的實現上可以看到。

        這些函式的實現是在event.c檔案中的。定製功能的實現原理和

前一篇部落格中說到的定製實現原理是一樣的。如下:

#ifndef _EVENT_DISABLE_MM_REPLACEMENT

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;


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_set_mem_functions函式來定製自己的記憶體分配函式。雖然這個函式不做任何的檢查,但還是有一點要注意。這個三個指標,要麼全設為NULL(恢復預設狀態),要麼全部都非NULL。原因後面會說到。

        這些記憶體分配函式的實現是相當簡單。看看event_mm_malloc_

void *

event_mm_malloc_(size_t sz)

{

if (_mm_malloc_fn)

return _mm_malloc_fn(sz);

else

return malloc(sz);

}

        如果使用者定製了記憶體分配函式(_mm_malloc_fn不為NULL),那麼就直接呼叫使用者定製的記憶體分配函式。否則使用C語言標準庫提供的。其他幾個記憶體分配函式也是這樣實現的。這裡就不貼程式碼了。

        定製自己的記憶體分配函式需要注意的一些地方:

  • 替換記憶體管理函式影響libevent 隨後的所有分配、調整大小和釋放記憶體操作。所以必須保證在呼叫任何其他libevent函式之前進行定製。否則,Libevent可能用定製的free函式釋放C語言 庫的malloc函式分配的記憶體
  • malloc和realloc函式返回的記憶體塊應該具有和C庫返回的記憶體塊一樣的地址對齊
  • realloc函式應該正確處理realloc(NULL, sz)(也就是當作malloc(sz)處理)
  • realloc函式應該正確處理realloc(ptr, 0)(也就是當作free(ptr)處理)
  • 如果在多個執行緒中使用libevent,替代的記憶體管理函式需要是執行緒安全的
  • 如果要釋放由Libevent函式分配的記憶體,並且已經定製了malloc和realloc函式,那麼就應該使用定製的free函式釋放。否則將會C語言標準庫的free函式釋放定製記憶體分配函式分配的記憶體,這將發生錯誤。所以三者要麼全部不定製,要麼全部定製。

參考: