libumem使用和源码分析系列文章(二)

在使用libumem时,大家可能都有一点好奇,为什么系统会使用libumem封装的malloc,free这些内存管理函数去替换libc中的内存管理函数?其实答案就在malloc.c中的如下代码:

#ifdef __GLIBC__
static void __attribute__((constructor)) umem_malloc_init_hook(void)
{
	if (__malloc_hook != umem_malloc_hook) {
		umem_startup(NULL, 0, 0, NULL, NULL);
		__malloc_hook = umem_malloc_hook;
		__free_hook = umem_free_hook;
		__realloc_hook = umem_realloc_hook;
		__memalign_hook = umem_memalign_hook;
	}
}

void (*__malloc_initialize_hook)(void) = umem_malloc_init_hook;

#else
void __attribute__((constructor))
__malloc_umem_init (void)
{
	umem_startup(NULL, 0, 0, NULL, NULL);
}
#endif

针对上述代码,我们只需关注#ifdef __GLIBC__……#else这个部分,因为替换libc中的内存管理函数的魔法就在这个部分:

(1)__attribute__((constructor))

__attribute__是gcc的关键字,它允许用户声明一些属性。而constructor属性的含义则是被修饰的函数要在main()函数执行前执行。相对应地,还有一个destructor属性,则是在main()函数结束时执行。这对这个属性的讨论,大家可以参考stackoverflow上的一篇帖子

(2)__malloc_hook,__free_hook,__realloc_hook,__memalign_hook

这些其实是GNU C库提供的一些变量,程序通过修改这些变量,可以达到使用自己定义的malloc,free这些函数的目的。详细的解释可以参考:http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html

libumem使用和源码分析系列文章(一)

libumem是2001年由SUN的工程师Jeff Bonwick和Jonathan Adams开发的一个对应用程序进行内存管理的动态链接库。简单地讲,libumem通过提供一组替换C标准库的内存分配函数(malloc,free,realloc等等),从而可以使用户更容易发现和解决关于内存管理的bug。从Solaris 9(Update 3)开始,libumem作为Solaris操作系统的一个标准库提供给应用程序使用。现在libumem已经被移植到其它的平台上,这个网站(https://labs.omniti.com/labs/portableumem)不仅介绍了关于libumem的移植,并且还提供了源代码。从今天起,我打算写一组系列文章,通过对libumem的源代码分析,介绍如何使用libumem以及它的工作原理。

首先,我介绍一下如何使用libumem。这里有两个方法:
(1)通过使用LD_PRELOAD环境变量:
LD_PRELOAD=libumem.so;export LD_PRELOAD
这样就使用户程序使用的是libumem中提供的内存管理函数,而不是C标准库的函数。关于LD_PRELOAD,感兴趣的读者可以参考stackoverflow上的这篇帖子:http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick
(2)在链接程序时加上 -lumem选项。

当应用程序运行后,我们可通过以下简单的Dtrace脚本去检查程序是否使用的是libumem:

#!/usr/sbin/dtrace -qs

pid$1::malloc:entry
{
    trace(probemod);
}

这个脚本会输出使用哪个模块的malloc函数,如果输出的模块名是类似于“libumem.so.1”,那么就证明程序已经使用libumem了,否则就需要检查一下,看看问题在哪里。