C++中栈内存和堆内存

  • 1. 一个由C/C++编译的程序占用的内存分为以下几个部分:

1.1 栈区(stack)

        由编译器自动分配和释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。

1.2 堆区(heap)

        一般由程序员分配和释放,若程序员没有释放,则可能在程序结束时由操作系统(OS)回收。注意它与数据结构中的堆是两回事,其分配方式倒是类似于链表

1.3 全局区(静态区,static)

        全局变量和静态变量都存放在这里, 初始化了的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量存放在相邻的另一块区域(BSS)。程序结束后由系统释放。

1.4. 文字常量区

        常量字符串就是放在这里的。程序结束后由系统释放。

1.5 程序代码区

        存放函数体的二进制代码。

1.7 举例程序

int a = 0;                   // 全局初始化区 
char *p1;                    // 全局未初始化区
int main()
{
		int b;                   // 栈
		char s[] = "abc";        // 栈
		char *p2;                // 栈
		char *p3 = "123456";     // 123456在常量区,p3在栈上
		static int c = 0;        // 全局(静态)初始化区
		p2 = new char[20];       // 分配得来的10和20字节的区域就在堆区
		strcpy_s(p2,20,"abcde"); // 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方
		cout << (void*)p2 <<'\t'<< (void*)p3<<endl;
		return 0;
}

  

2. 数据结构中的栈与堆:

栈:连续存储的数据结构,具有先进后出的性质。通常的操作有入栈(压栈)、出栈和栈顶元素。想要读取栈整那个的某元素,就需要将其之前的所有元素出栈才能完成,类似现实生活中的箱子。

堆:非连续的树形储存数据结构,每个节点有一个值,整棵树是经过排序的。特点是根节点的值最小(或最大),且根节点的两个子树也是一个堆。常用来实现优先队列,存取随意。

3. 内存中的栈区堆区


一般说到的内存是RAM,计算机内存的大致划分如下:

栈内存:由程序自动向操作系统申请分配以及回收,速度快,使用方便,但程序员无法控制。若分配失败,则提示栈溢出错误。注意,const局部变量也储存在栈区内,栈区向地址减小的方向增长。

//测试栈内存
#include <iostream>
int main()
{
    int i = 10; //变量i储存在栈区中
    const int i2 = 20;
    int i3 = 30;
    std::cout << &i << " " << &i2 << " " << &i3 << std::endl;
    return 0;
}


测试输出为:

&i3 < &i2 < &i,证明地址是减小的。

堆内存:程序员向操作系统申请一块内存,当系统收到程序的申请时,会遍历一个记录空闲内存地址的链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。分配的速度较慢,地址不连续,容易碎片化。此外,由程序员申请,同时也必须由程序员负责销毁,否则则导致内存泄露

//测试堆内存和栈内存的区别
#include <iostream>
int main()
{
    int i = 10; //变量i储存在栈区中
    char pc[] = "hello!"; //储存在栈区
    const double cd = 99.2; //储存在栈区
    static long si = 99; //si储存在可读写区,专门用来储存全局变量和静态变量的内存
    int* pi = new int(100); //指针pi指向的内存是在 堆区,专门储存程序运行时分配的内存
    std::cout << &i << " " << &pc << " " << &cd << " " << &si << " " << pi << std::endl;
    delete pi; //需程序员自己释放
    return 0;
}

测试输出:

  运行多次发现pi所指向的地址是跳跃的;静态/全局变量&si储存在可读写去;前三个变量储存在栈中,由程序自动分配和销毁。

3.1 申请方式的比较

3.1.1 栈

        由系统(编译器)自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间。

3.1.2 堆

        需要程序员自己申请,并指明大小。

        在C中使用malloc函数(释放时使用free函数),如p1 = (char *)malloc(10);

        在C++中使用new运算符(释放时使用delete运算符),如p2 =  new char[20];

        但是注意p1和p2本身是在栈中的。

 

3.2 申请后系统的响应比较

3.2.1 栈

        只要栈的剩余空间大于所申请空间,系统就会为程序分配内存,否则将报异常提示栈溢出。

3.2.2 堆

        首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的内存大小,这样,代码中的delete语句才能正确地释放该内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动将多余的那部分重新放入空闲链表中。

 

3.3 申请内存大小的限制

3.3.1 栈

        在Windows下,栈是向低地址扩展的,是一块连续的内存区域。这句话的意思是,栈顶的地址和栈的最大容量是系统预先规定好的,在 Windows下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

3.3.2 堆

        堆是向高地址扩展的,是不连续的内存区域。这是由于系统是用链表来存储空闲内存地址的,自然也就不连续,而且链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

 

 

 

 

 



 

转载于:https://www.cnblogs.com/vincent-syr/p/7894739.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值