分配方式
- 堆内存分配:
- 使用函数如
malloc
、calloc
、realloc
等来手动分配内存。例如,int *ptr = (int *)malloc(sizeof(int));
通过malloc
函数向操作系统请求一块指定大小的内存空间,返回一个指向该内存起始地址的指针。分配的内存位置是由操作系统的堆管理器在堆空间中动态确定的,不一定是连续的内存块。
- 栈内存分配:
- 当函数被调用时,其局部变量在栈上自动分配内存。例如,在函数
void func() { int num; }
中,num
变量在函数func
被调用时,会在栈上自动分配一个int
类型大小的内存空间。栈内存的分配是由编译器自动处理的,按照一定的规则(通常是后进先出),分配的内存是连续的,并且随着函数调用的结束自动释放。
生命周期
- 堆内存分配:
- 生命周期从调用内存分配函数(如
malloc
)成功开始,直到调用相应的释放函数(如free
)为止。如果在程序中没有及时调用free
释放堆内存,会导致内存泄漏。例如,下面的代码中如果没有free(ptr)
,ptr
指向的堆内存一直不会被释放:
int *ptr = (int *)malloc(sizeof(int));
// 使用ptr
// 没有free(ptr)会导致内存泄漏
- 栈内存分配:
- 栈内存中局部变量的生命周期与函数的调用和返回紧密相关。当函数被调用时,局部变量在栈上分配内存,函数执行结束时,栈上为这些局部变量分配的内存自动被释放。例如:
void func() {
int num = 10;
// num在函数调用时分配内存
}
// 函数结束,num占用的栈内存自动释放
内存管理
- 堆内存分配:
- 开发者需要手动管理堆内存的释放。在使用完堆内存后,必须调用
free
函数释放已分配的内存,否则会造成内存泄漏。例如:
int *ptr = (int *)malloc(sizeof(int));
// 使用ptr
free(ptr);
- 堆内存的分配和释放可能会导致内存碎片的产生。频繁的分配和释放不同大小的内存块,可能会使得堆中出现一些不连续的空闲内存块,这些小块内存无法满足后续较大内存分配请求,从而降低内存的使用效率。
- 栈内存分配:
- 编译器自动管理栈内存的分配和释放,开发者无需手动干预。当函数返回时,栈帧被销毁,栈上的局部变量内存自动释放。这使得栈内存管理相对简单,不容易出现内存泄漏问题。但栈的大小通常是有限的,如果局部变量过多或者递归调用过深,可能会导致栈溢出错误。例如:
void recursiveFunc() {
int largeArray[1000000];
recursiveFunc();
// 可能导致栈溢出
}