malloc,realloc,calloc对比

malloc

作用区域 堆区

函数声明 :void *malloc(size_t size);
       对于申请后的内存的初始值:0xcdcdcdcd
函数返回值:
       如果分配成功则返回指向被分配内的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。

内存管理方式
malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内块时,一定要进行返回值的判断。Linux Libc6采用的机制是在free的时候试图整合相邻的碎片,使其合并成为一个较大的free空间。
头文件:#include<stdlib.h> #include<malloc.h>

使用场合
动态内存分配,链表。当需要在内存的动态存储区中分配一块长度为num_bytes字节的连续区域时。参数num_bytes为 需要的内
存空间的长度,返回该区域的地址。malloc在动态分配完内存后不对分配的内存空间初始化,里边数据是随机的垃圾数据.

realloc

作用区域:堆区

函数原型:void *realloc( void *memblock, size_t size );

初始值:0xcdcdcdcd
返回值:
(1)返回的是一个void类型的指针:调用成功。(这就要求在你需要的时候进行强制类型转换)
(2)返回NULL:当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL时。此时原内存变成“free(游离)”的了。
(3)返回NULL:当没有足够的空间可供扩展的时候。此时,原内存空间的大小维持不变。

内存管理方式:
"如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address。这里说的是“扩大”,我们知道,
realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,
如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小 =
newsize。那么就ok。得到的是一块连续的内存。 如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一
块newsize大小的内存。并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针。(数据被移动了)。
老块被放回堆上。(其余和mallloc类型)

头文件:#include<stdlib.h> #include<malloc.h>

使用场合:调整已经申请的内存空间大小。当需要在内存的动态存储区中分配n个长度为size_t size字节的连续空间时。如果分配成功,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL

calloc

作用区域:堆区

函数原型:void *calloc(size_t n, size_t size);

初始值:0

函数返回值:
      在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。。如果内存分配失败,或者请求的内存数量超过 _HEAP_MAXREQ,那么 calloc 设置 errno 为 ENOMEM

内存管理方式:

在malloc基础上,初始化了被申请的内存区域

使用场合:

动态分配内存。:当需要在已经被(malloc(), calloc(), 或realloc())分配的空间的基础上重新分配空间时。参数mem_address为原有的空间地址,newsize是重新申请的地址空间。(1)传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的。(2)如果realloc需要的内存小于原来的内存大小,会导致数据丢失;如果原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 如果原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址。(3)如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回NULL。而原来的内存块保持不变。(4)如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL(5)如果mem_address为NULL,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针

三者的释放方式:

 void free(void *ptr);(与malloc()函数配对使用,释放malloc函数申请的动态内存。(另:对于free(p)这句语句,如果p 是NULL 指针,那么free 对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。))。如果对一个不是上面三个函数申请的内存free,结果是未定义的。


三者的最大分配:

如果内存分配失败,或者请求的内存数量超过 _HEAP_MAXREQ,那么 malloc 设置 errno 为 ENOMEM

补充:brk和mmap

在Linux中,对于heap区的操作提供的是brk()系统调用,C运行库又提供了sbrk()库函数。而对于与mmap区则提供的是mmap()和munmap()函数。在C中的malloc函数的底层主要就是使用了brk()和mmap()系统调用,它们的区别也从上面可以看出来,在<128K内存申请的时候,linux内核调用的是brk(),而>=128K的时候则是调用了mmap(). 两者申请的都是虚拟内存,并不是物理内存,只有当真正要访问的时候该内存的时候,就会产生缺页中断,然后陷入内核,操作系统根据资源情况分配物理内存,然后建立虚拟地址到物理地址的映射关系(写时)(《程序员的自我修养》 && https://blog.csdn.net/gamebot/article/details/79368323)。简略来说,申请大于128k的内存时,brk向上移动到申请的内存的地方。大于时,调用mmap映射内存,在mmap区(也就是heap堆和栈之间的一块区域区分配虚拟内存)申请了一块200K的内存。


参考资料:《程序员的自我修养》,《深入理解计算机系统·》


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值