【 C/C++】变量在内存里的存储区域

C/C++语言在内存中一共分为如下几个区域,分别是:

  1. 内存栈区: 编译期间就能确定存储大小,运行时自动分配释放。存放函数的参数值、返回地址、局部变量的值等。在函数作用域内创建,在离开作用域后自动销毁。.esp 始终指向栈顶, 栈中的数据越多, esp的值越小。其操作方式类似于数据结构中的栈。
    存储空间是连续的,两个紧密挨着定义的局部变量,他们的存储空间也是紧挨着的。栈的大小是有限的,通常Visual C++编译器的默认栈的大小为1MB,所以不要定义int a[1000000]这样的超大数组。

  2. 内存堆区: 存放new或者malloc出来的对象,一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。动态分配得到的内存区域附带有分配信息, 所以你能够 free和delete它们。
    存储空间是不连续的,一般由malloc(或new)函数来分配内存块,并且需要用free(delete)函数释放内存。C/C++不提供垃圾回收机制,因此需要对堆中的数据进行及时销毁,如果程序员没有释放掉,那么就会出现常说的内存泄漏问题。需要注意的是,两个紧挨着定义的指针变量,所指向的malloc出来的两块内存并不一定的是紧挨着的,所以会产生内存碎片。另外需要注意的一点是,堆的大小几乎不受限制,理论上每个程序最大可达4GB。

  3. 静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW), 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(ZI)。程序结束后由系统释放
    和“栈”一样,通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。

  4. 常量区: 存放局部变量或者全局变量的值,常量字符串就是放在这里的。 程序结束后由系统释放 (RO)
    和“全局/静态存储区”一样,通常是用于那些在编译期间就能确定存储大小的常量的存储区,并且在程序运行期间,存储区内的常量是全局可见的。这是一块比较特殊的存储去,他们里面存放的是常量,不允许被修改。

  5. 代码区:存放函数体的二进制代码。 (RO)

栈、堆 对比
存储内容 局部变量 变量
作用域 函数作用域、语句块作用域 函数作用域、语句块作用域
编译期间大小是否确定
大小 1MB 4GB
内存分配方式 地址由高向低减少 地址由低向高增加
内容是否可以修改
全局/静态存储区、常量存储区 对比
全局/静态存储区 常量存储区
存储内容 全局变量、静态变量 常量
编译期间大小是否确定
内容是否可以修改

扒了一张图,这张图中所示内存空间,地址由下往上增长,分别标示了 .text、.data、.bss、stack和heap的内存分部情况。 我们可以看到:
在这里插入图片描述

text、data(gvar)、bss 在内存中地址较低低的位置(low level address),而堆栈则在相对较高的位置。
堆(Heap)往高地址方向生长,栈(Stack)往低地址方向生长。

知道如上一些内存分配机制,有助于我们理解指针的概念。

动&静

一个程序被加载到内存中,这块内存首先就存在两种属性:静态分配内存和动态分配内存。
静态分配内存:是在程序编译和链接时就确定好的内存。
动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存。

Text & Data & Bss

  • .text: 也称为代码段(Code),用来存放程序执行代码,同时也可能会包含一些常量(如一些字符串常量等)。该段内存为静态分配,只读(某些架构可能允许修改)。
    这块内存是共享的,当有多个相同进程(Process)存在时,共用同一个text段。

  • .data: 也有的地方叫GVAR(global value),用来存放程序中已经初始化的非零全局变量。静态分配。
    data又可分为读写(RW)区域和只读(RO)区域。
    -> RO段保存常量所以也被称为.constdata
    -> RW段则是普通非常全局变量,静态变量就在其中

  • .bss: 存放程序中为初始化的和零值全局变量。静态分配,在程序开始时通常会被清零。

text和data段都在可执行文件中,由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。
这三段内存就组成了我们编写的程序的本体,但是一个程序运行起来,还需要更多的数据和数据间的交互,否则这个程序就是死的,无用的。所以我们还需要为更多的数据和数据交互提供一块内存——堆栈。

重点说下 堆(Heap)、栈(Stack)
1) 堆(Stack)向高内存地址生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
2) 栈(Stack)向低内存地址生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
3) 堆和栈相向而生,堆和栈之间有个临界点,称为stkbrk。
4) 堆和栈都是动态分配内存,两者空间大小都是可变的。每个线程都会有自己的栈,但是堆空间是共用的。

Tips:

char* p = new char[20];
// 这行代码在Heap中开辟了20个char长度的空间,同时在Stack上压入了p,
// 指针变量p存在于栈上,
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值