C语言的内存管理

堆和栈的区别:

栈的特征

执行的速度相对较快;

空间较小;

生存期由系统决定;

作用域较小;

有名空间,可以通过变量名或者数据名访问;

堆的特征

执行的速度相对较慢;

空间较大;

生存期由“自己”决定,malloc申请,free释放;

作用域很大(整个程序都可以访问);

无名空间,只能通过指针使用;

C语言空间的申请

malloc

功能:

分配 size 字节的未初始化内存。若分配成功,则返回指向分配内存块最低位(首位)字节的,为任何拥有基础对齐的对象类型对齐的指针。

头文件:

#include<stdlib.h>
原型:
void* malloc( size_t size );

参数:

size - 要分配的字节数

返回值:

成功时:返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。

失败时:返回空指针。

说明:

malloc申请的空间为连续空间;malloc申请的是没有初始化的空间;

返回值类型是void * 该类型表明malloc返回的地址空间中的数据类型是不确定,必须经过强制类型转换才可以使用。

realloc

功能:

先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。

头文件:

#include <stdlib.h>
原型:
extern void *realloc(void *mem_address, unsigned int newsize);

参数:

mem_address - 当前的指针

newsize - 重新分配空间的大小

返回值:

如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

说明:

如果mem_address为NULL,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针。

如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL。

如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回NULL。而原来的内存块保持不变。

假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址

如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。

传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的

传递给realloc的指针可以为空,等同于malloc。

实例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char *str;
 
   /* 最初的内存分配 */
   str = (char *) malloc(15);
   strcpy(str, "runoob");
   printf("String = %s,  Address = %p\n", str, str);
 
   /* 重新分配内存 */
   str = (char *) realloc(str, 25);
   strcat(str, ".com");
   printf("String = %s,  Address = %p\n", str, str);
 
   free(str);
   
   return(0);
}

calloc

功能:

在内存的动态存储区中分配num个长度为size的连续空间;

头文件:

#include <stdlib.h>
原型:
void* calloc(unsigned int num,unsigned int size);

参数:

num - 对象个数

size - 对象占据的内存字节数,相较于malloc函数,calloc函数会自动将内存初始化为0

返回值:

成功时,返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。

失败时,返回空指针。

说明:

因为对齐需求的缘故,分配的字节数不必等于 num*size 。

初始化所有位为零不保证浮点数或指针被各种初始化为 0.0 或空指针(尽管这在所有常见平台上为真)。

因为calloc()函数会清空分配的内存,而malloc()函数不会,所以可以调用以“1”作为第一个实参的calloc()函数,为任何类型的数据项分配空间。

实例:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int i;
    int* pn = (int*)calloc(10, sizeof(int));
    for(i = 0;i < 10;i++)
        printf("%d", pn[i]);
    printf("\n");
    free(pn);
    return 0;
}

alloca

功能:
alloc是在栈(stack)上申请空间,该变量离开其作用域之后被自动释放,无需手动调用释放函数。
头文件:
#include<stdlib.h>
原型
void * __cdecl  alloca(size_t);

参数:

size - 要分配的字节数

返回值:

函数返回一个指向申请到的空间的void型指针.

说明:

在某些系统中会宏定义成_alloca使用.

不提倡使用此函数:

在调用 alloca() 的函数返回的时候, 它分配的内存会自动释放。也就是说, 用 alloca 分配的内存在某种程度上局部于函数的“堆栈帧”或上下文中。

alloca() 不具可移植性, 而且在没有传统堆栈的机器上很难实现。 当它的返回值直接传入另一个函数时会带来问题, 如 fgets(alloca(100), 100, stdin)。

由于这些原因, alloca() 不合标准, 不宜使用在必须广泛移植的程序中, 不管它可能多么有用。 既然 C99 支持变长数组(VLA), 它可以用来更好的 完成 alloca() 以前的任务。

C语言空间的释放

free

原型:

void free(void *ptr);

功能:

释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

头文件:

#include <stdlib.h>

参数:

ptr - 要释放的空间的指针

返回值

该函数不返回任何值。

说明:

不能传NULL;

不能释放已经被释放的空间;

不能使用已经被释放的空间;

当程序运行过程中申请了空间,但是没有free的话,会造成内存泄漏.一部分的内存没有被使用,但是由于没有free,因此系统认为这部分内存还在使用,造成不断的向系统申请内存,使得系统可用内存不断减少.但是内存泄漏仅仅指程序在运行时,程序退出时,OS将回收所有的资源.因此,适当的重起一下程序,有时候还是有点作用.

malloc函数详细说明

在C语言中只能通过malloc()和其派生的函数进行动态的申请内存,而实现的根本是通过系统调用实现的(在linux下是通过sbrk()系统调用实现)。

malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

malloc()在运行期动态分配分配内存,free()释放由其分配的内存。malloc()在分配用户传入的大小的时候,还分配的一个相关的用于管理的额外内存,不过,用户是看不到的。所以,实际的大小 = 管理空间 + 用户空间,malloc(0)的有效内存大小为24,32位中为12,准确的说是至少是这么多,并且这些内存是可以用的。

#include<stdio.h>
#include<stdlib.h>

int main()
{
    char *p=(char *)malloc(0);
    char *p1=(char *)malloc(5);
    char *p2=(char *)malloc(25);
    char *p3 = (char *)malloc(39);
    char *p4 = (char *)malloc(41);

    printf("p size:%d\n",malloc_usable_size(p));
    printf("p1 size:%d\n", malloc_usable_size(p1));
    printf("p2 size:%d\n", malloc_usable_size(p2));
    printf("p3 size:%d\n", malloc_usable_size(p3));
    printf("p4 size:%d\n", malloc_usable_size(p4));

    free(p);
    free(p1);
    free(p2);
    free(p3);
    free(p4);
    return 0;
}

8a617568-3b2d-4c10-8c62-91b6e9a7d0b9

此外,堆中的内存块总是成块分配的,并不是申请多少字节,就拿出多少个字节的内存来提供使用。堆中内存块的大小通常与内存对齐有关(8Byte(for 32bit system)或16Byte(for 64bit system)。

因此,在64位系统下,当(申请内存大小+sizeof(struct mem_control_block) )% 16 == 0的时候,刚好可以完成一次满额的分配,但是当其!=0的时候,就会多分配内存块。

posted @ 2019-08-02 01:19  WindSun  阅读(424)  评论(0编辑  收藏  举报
博客已停更,文章已转移,点击访问