写在前面:
这个源码是分析libevent-2.0.20-stable, 并非最新版本的libevent,作者并没有全看源码,在这里会推荐以下参考的一些网站,也欢迎大家在不足的地方提出来进行讨论。
libevent源码分析
libevent深度剖析1
libevent深度剖析2
什么都没包装的内存管理
默认情况下,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.在多线程的情况下要求线程安全