为什么编译程序提供了两个版本的malloc()函数?
包含了头文件stdlib.h后,你就可以在程序中使用malloc()和free()函数了。这些函数是编译程序从C函数库中包含到你的程序中的。有些编译程序还提供了一个独立的库,你可以要求编译程序用其中的版本来代替标准库中的malloc()和free()版本(只需在命令行中加入类似一lmalloc这样的标志)。
malloc()和free()的替代版本和标准版本的功能完全一样,只不过前者被认为在对内存分配错误不那么宽容的代价下,能产生更好的执行效果。笔者在15年的C语言编程经历中从未使用过这些替代版本,但为了回答这个问题,笔者编写了一个大量使用malloe()和free()的简单的测试程序,并用一种非常著名的C编译程序,分使用和不使用malloc库两种情况对其进行了编译。结果笔者没有发现明显的差异,并且笔者怀疑该开发商在实现这两种版本时使用了相同的代码,因为两个版本的程序的大小是一样的。正因为如此,笔者也就不便指出该开发商的名字了。
以上的情况说明,也许不必去使用malloc()的其它版本,并且也不要指望它们会提高程序的性能。如果剖视(profiling)表明程序把大量时间花费在malloc()和free()上,并且通过改进算法也无法解决这个问题,那么你可以自己编写一个“缓冲池(pool)”分配函数,也许能提高程序的性能。
大量调用malloc()和free()函数的程序往往是为相同类型的数据分配内存和释放内存,这些数据具有固定的长度。当知道要分配和释放的数据的大小后,自己编写的缓冲池分配函数会比malloc()和free()运行得更快。一个缓冲池分配函数的工作方式是这样的:调用malloc()一次分配许多大小相同的结构,然后每次交付一个供使用。该函数通常从来不调用free(),它所使用的内存将一直保留到程序退出。例12.12给出了一个用于自定义类型struct foo的缓冲池分配函数。
例12.12一个缓冲池分配函数的例子
# include <stdio. h>
/ * declaration of hypothetical structure "foo" * /
struct foo {
int dummy1;
char dummy2;
long dummy3;
};
/ * start of code for foo pool allocator * /
# include <stdlib. h>
/ * number of foos to mallocO at a time * /
# define NFOOS 64
/*
* A union is used to provide a linked list that
* can be overlaid on unused foos.
*/
union foo_u {
union foo_u *next;
struct foo f;
};
static union foo_u * free_list ;
struct foo *
alloc_foo()
{
struct foo * ret = 0;
if (!free_list) {
int i;
free_list = (union foo_u * ) malloc(NFOOS
* sizeof (union foo_u));
if (free_list) {
for (i = 0; i<NFOOS-1; i+ + )
free_list[i]. next =
&iree_list[i + 1];
free_list [NFOOS -1 ]. next = NULL;
if (free_list) {
ret = &free_list ->f;
free_list = free_list ->next;
}
return ret;
}
void
free_foo(struct foo * fp)
{
union foo_u * up= (union foo_u * ) fp;
up ->next = free_list)
free_list = up;
}
int
main(int argc, char * * argv)
{
int i;
int n;
struct foo ** a ;
if (argc <2) {
fprintf(stderr, "usage: %s f\n" , argv[0]);
fprintf(stderr. "where f is the number of");
fprintf(stderr, "'foo's to allocate\n" ) ;
exit(1);
}
i = atoi(argv[l]);
a = (struct foo * * ) malloc(sizeof (struct foo * ) * i);
for (n = 0; n<i; n+ + )
a[n] = alldc-foo() ;
for (n = 0j n<i; n+ + )
free_foo(a[n]);
return 0;
}
笔者用30000这样一个参数编译并运行了上述程序,并将其结果与用malloc()和free()代替alloc_foo()和free_foo()的一个类似的程序进行比较,发现前者使用的CPU时间为O.46秒,而后者为0.92秒。
需要注意的是,使用缓冲池分配函数只能是最后的选择,它也许能提高速度,但它会造成内存的巨大浪费。此外,如果你不调用free(),而又没能小心地把从缓冲池中申请到的内存返回去,就会导致微妙的内存分配错误。
malloc()和free()的替代版本和标准版本的功能完全一样,只不过前者被认为在对内存分配错误不那么宽容的代价下,能产生更好的执行效果。笔者在15年的C语言编程经历中从未使用过这些替代版本,但为了回答这个问题,笔者编写了一个大量使用malloe()和free()的简单的测试程序,并用一种非常著名的C编译程序,分使用和不使用malloc库两种情况对其进行了编译。结果笔者没有发现明显的差异,并且笔者怀疑该开发商在实现这两种版本时使用了相同的代码,因为两个版本的程序的大小是一样的。正因为如此,笔者也就不便指出该开发商的名字了。
以上的情况说明,也许不必去使用malloc()的其它版本,并且也不要指望它们会提高程序的性能。如果剖视(profiling)表明程序把大量时间花费在malloc()和free()上,并且通过改进算法也无法解决这个问题,那么你可以自己编写一个“缓冲池(pool)”分配函数,也许能提高程序的性能。
大量调用malloc()和free()函数的程序往往是为相同类型的数据分配内存和释放内存,这些数据具有固定的长度。当知道要分配和释放的数据的大小后,自己编写的缓冲池分配函数会比malloc()和free()运行得更快。一个缓冲池分配函数的工作方式是这样的:调用malloc()一次分配许多大小相同的结构,然后每次交付一个供使用。该函数通常从来不调用free(),它所使用的内存将一直保留到程序退出。例12.12给出了一个用于自定义类型struct foo的缓冲池分配函数。
例12.12一个缓冲池分配函数的例子
# include <stdio. h>
/ * declaration of hypothetical structure "foo" * /
struct foo {
int dummy1;
char dummy2;
long dummy3;
};
/ * start of code for foo pool allocator * /
# include <stdlib. h>
/ * number of foos to mallocO at a time * /
# define NFOOS 64
/*
* A union is used to provide a linked list that
* can be overlaid on unused foos.
*/
union foo_u {
union foo_u *next;
struct foo f;
};
static union foo_u * free_list ;
struct foo *
alloc_foo()
{
struct foo * ret = 0;
if (!free_list) {
int i;
free_list = (union foo_u * ) malloc(NFOOS
* sizeof (union foo_u));
if (free_list) {
for (i = 0; i<NFOOS-1; i+ + )
free_list[i]. next =
&iree_list[i + 1];
free_list [NFOOS -1 ]. next = NULL;
if (free_list) {
ret = &free_list ->f;
free_list = free_list ->next;
}
return ret;
}
void
free_foo(struct foo * fp)
{
union foo_u * up= (union foo_u * ) fp;
up ->next = free_list)
free_list = up;
}
int
main(int argc, char * * argv)
{
int i;
int n;
struct foo ** a ;
if (argc <2) {
fprintf(stderr, "usage: %s f\n" , argv[0]);
fprintf(stderr. "where f is the number of");
fprintf(stderr, "'foo's to allocate\n" ) ;
exit(1);
}
i = atoi(argv[l]);
a = (struct foo * * ) malloc(sizeof (struct foo * ) * i);
for (n = 0; n<i; n+ + )
a[n] = alldc-foo() ;
for (n = 0j n<i; n+ + )
free_foo(a[n]);
return 0;
}
笔者用30000这样一个参数编译并运行了上述程序,并将其结果与用malloc()和free()代替alloc_foo()和free_foo()的一个类似的程序进行比较,发现前者使用的CPU时间为O.46秒,而后者为0.92秒。
需要注意的是,使用缓冲池分配函数只能是最后的选择,它也许能提高速度,但它会造成内存的巨大浪费。此外,如果你不调用free(),而又没能小心地把从缓冲池中申请到的内存返回去,就会导致微妙的内存分配错误。