分类: LINUX
2012-01-10 22:10:13
++++++APUE读书笔记-07进程环境(3)++++++
8、内存分配
================================================
ISO C指定了三种内存分配的方式:
#include
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
这三种函数如果返回的指针是非空的表示分配成功,如果出错了那么返回的是null.
void free(void *ptr);
malloc分配指定字节大小的内存,内存里面的数据是不确定的。
calloc分配nobj个特定大小(size)的对象,内存里面的数据被初始化为0。
realloc用来增加或者减小之前分配的内存区域。如果是增加的话,可能会把原先的分配的区域移动到别的地方然后在后面增加多出来的内存,增加的内存的内容不确定并返回新内存块的指针,如果原来的区域后面有足够的空间来增加额外的内存的话就不需要移动内存了。参数是最终内存的总大小。如果ptr为空那么realloc的行为和malloc的行为是一样的。
三种分配函数返回的指针的对齐方式保证适合任何的数据类型。因为函数返回的是void*所以如果我们包含了stdlib.h那么我们不用强制将这个函数返回的指针转换成为我们想要的类型。
free使用来释放之前分配的内存的。
分配函数是使用sbrk系统来进行实现的。实际上分配的空间要比指定的空间大一些,因为需要存放空间大小等信息让free正确地执行。如果只分配不释放会导致内存泄露,如果释放了没有分配的内存,那么会导致致命的错误。
由于这些函数导致的内存错误很难跟踪,所以有些系统提供了这些函数的可以进行一些额外检测的版本(当alloc或者free时)。可以通过包含一些库文件或者有时候也可以通过特定的编译选项来打开这些额外检查的特性。
下面是一个使用sbrk的例子:
/*测试用sbrk分配内存
* #include
* int brk(void *addr);
* void *sbrk(intptr_t increment);
* brk和sbrk用来改变程序数据段的结尾地址。如果地址增加了表示为这个进程分配内存了,如果地址减少了表示给这个进程释放内存了。
* sbrk把程序的结尾地址增加increment,如果increment的值为0会返回当前程序的结尾地址。返回先前的程序结尾,如果之前已经增加过那么返回上次的新的程序结尾(不是设置完了之后的),失败了就返回-1,同时errno被设置为ENOMEM.
*
* 一个可能的输出结果是:
* current break is:153415680
* after add break is:153415680
* after sub break is:153415690
* current break is:153415680
*
* malloc就是用这个系统调用实现的。
* */
#include
#include
int main(int argc, char *argv[])
{
void *cur = sbrk(0);
printf("current break is:%d\n",(int)cur);//
void *newadd1 = sbrk(10);
printf("after add break is:%d\n",(int)newadd1);//
void *newsub1 = sbrk(-10);
printf("after sub break is:%d\n",(int)newsub1);//
cur = sbrk(0);
printf("current break is:%d\n",(int)cur);//
return 0;
}
一些其他的内存分配函数:
除了前面提到的malloc,free等标准分配函数,还有一些替代的内存分配函数。有些系统只提供了标准的分配函数,开发者可以自己选择下载其他的替代分配函数来使用。
libmalloc
SVR4-based的系统,例如solaris,包含libmalloc库,这个库提供了一系列的和ISO C内存分配函数相匹配的接口。libmalloc库包括mallopt函数,这个函数允许进程设置特定的变量来控制存储的分配(???)。还有一个函数叫做mallinfo,可以用来提供内存分配器的统计信息。
vmalloc
这是一种允许进程对不同的内存区域使用不同的技术分配内存的内存分配器。出了vmalloc之外,这个库也提供了ISO C内存分配函数的模拟版本。
quick-fit
以前标准的分配算法使用的是最佳适配或者最先适配分配策略。Quick-fit比这两种方法都快,但是它会消耗更多的内存。这个算法基于把内存分成不同大小的缓存块,然后基于缓存的大小,在free list上面维护没有使用的缓存。在一些ftp站点上面有基于quick-fit实现的malloc和free。
alloca Function
还有一个值得一提的函数就是alloca.这个函数和malloc具有一样的调用次序,然而它不是从heap上面分配内存而是从当前函数所处堆栈上面分配内存的。这样的有时就是我们不用释放空间了,当函数结束的时候内存的空间会自动地被释放掉。alloca函数导致堆栈桢的大小增加。这样的缺点是有些系统不支持alloca函数,因为对于它们而言不可能在调用函数之后再增加堆栈桢的大小。然而许多的软件包还是使用了它,因为这个函数在许多系统上都有实现。
参考: