本文隶属于专题系列: 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函数分配的内存
  • mallocrealloc函数返回的内存块应该具有和C库返回的内存块一样的地址对齐
  • realloc函数应该正确处理realloc(NULL, sz)(也就是当作malloc(sz)处理)
  • realloc函数应该正确处理realloc(ptr, 0)(也就是当作free(ptr)处理)
  • 如果在多个线程中使用libevent,替代的内存管理函数需要是线程安全的
  • 如果要释放由Libevent函数分配的内存,并且已经定制了mallocrealloc函数,那么就应该使用定制的free函数释放。否则将会C语言标准库的free函数释放定制内存分配函数分配的内存,这将发生错误。所以三者要么全部不定制,要么全部定制。

参考:

        http://www.wangafu.net/~nickm/libevent-book/Ref1_libsetup.html

你可能感兴趣的内容
0条评论

dexcoder

这家伙太懒了 <( ̄ ﹌  ̄)>
Owner