内存分配
堆(heap):堆存储的内容一般由用户申请和释放,若用户没有释放一般在程序运行完成以后,由操作系统回收。一般由new,malloc申请的变量才存放在堆中。
栈(stack):栈由编译器(compiler)自动申请和释放,函数参数及调用地址,局部变量的值都存放在栈中。
大小及存储结构方式
堆:内存分配的堆不同于数据结构里的堆。内存分配的堆存放内容并不连续,而是类似于链表的分配方式。操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
windows下,堆的大小一般等于虚拟内存的大小,一般是1G。
栈:在windows下,栈是一块连续的区域,并且栈顶地址及栈的容量是系统设置好的,即栈的大小固定,同时由高地址向地址扩展。
栈的大小一般较小,为1M左右,所以可申请的空间较小,当申请空间超过栈大小的时候会报“stackoverflow”的错。
测试本机大致栈的大小
#include <stdlib.h>
#include <iostream>
#include <windows.h>
using namespace std;
int stackApp(int & count)
{
int a = 1;
while (1)
{
_asm{ push a} //消耗栈空间;
count++;
}
}
int main(int argc, char* argv[])
{
int count = 0;
__try{
stackApp(count);
}
__except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH){
cout << "exception" << endl;
cout << "the count is " << (count * 4 / 1024) << "kB" << endl;
}
system("pause");
return 0;
}
博主本机输出1010KB,约为1M。
优缺点比较
堆:是由new,malloc分配的内存,一般速度比较慢,而且容易产生内存碎片,但可申请的内存大(1G)。
栈:由系统自动分配,速度较快,但程序员是无法控制的,并且可申请的内存小(1M)。
一个例子
int* pFun()
{
int p[2];//开辟空间是在栈区,由系统申请和释放
p[0] = -2;
p[1] = -1;
return p;
}
int main(int argc, char* argv[])
{
int *p = pFun();
int A[20] = { -300 };//申请局部变量,存在栈上
cout << p[0] << p[1] << endl;
return 0;
}
int p[2]语句开辟的空间是在栈区,由系统分配和释放,在函数返回以后又向栈区申请空间原来返回地址可能已经被重新赋值。此时输出p[0] , p[1],值不为函数体内赋的值。
int* pFun()
{
int *p = new int[2];//开辟空间在堆区,由程序员申请和释放
p[0] = -2;
p[1] = -1;
return p;
}
int main(int argc, char* argv[])
{
int *p = pFun();
int A[20] = { -300 };//申请局部变量,存在栈上
cout << p[0] << p[1] << endl;
return 0;
}
当int *p = new int[2]时,开辟空间是在堆区,由用户分配和释放。为delete[]之前p所在的地址不会被重新分配。此时输出p[0] , p[1],值对。
C/C++内存分配和占用
- 栈区(stack)
由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 - 堆区(heap)
一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 - 全局区(静态区)(static)
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 - 文字常量区
常量字符串就是放在这里的。 程序结束后由系统释放 - 程序代码区
存放函数体的二进制代码。
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}