C程序的存储布局

一个由 C/C++编译的程序占用的内存(memory)分为以下几个部分:

1. 程序代码区(.text):存放函数体的二进制代码  。

2. 文字常量区(.rodata):常量字符串就是放在这里的,程序结束后由系统释放(rodata—read only data)。

3. 全局区/静态区(static):全局变量 和 静态变量的存储是放在一块的。初始化的全局变量和静态变量在一块区域(.rwdata or .data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss), 程序结束后由系统释放。*在 C++中,已经不再严格区分bss和 data了,它们共享一块内存区域

4. 堆区(heap):一般由程序员分配释放(new/malloc/calloc delete/free),若程序员不释放,程序结束时可能由 OS 回收。

注意:它与数据结构中的堆是两回事,但分配方式倒类似于链表。

5. 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方法类似与数据结构中的栈。

如下面两幅图:


就上面两幅图,说明以下几点:

1.堆和栈的区别

管理方式:对于栈来讲,是由编译器自动管理;对于堆来说,释放工作由程序员控制,容易产生 memory leak。

空间大小:一般来讲在 32 位系统下,堆内存可以达到接近 4G 的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在 VC6 下面,默认的栈空间大小大约是 1M。

碎片问题:对于堆来讲,频繁的new/delete 势必会造成内存空间的不连续,从而造成大量碎片,使程序效率降低;对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,永远都不可能有一个内存块从栈中间弹出。

生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆;栈有 2 种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配,动态分配由 alloca 函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,不需要我们手工实现。

分配效率:栈是机器系统提供的数据结构,计算机会在底层分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高;  堆则是 C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,然后进行返回。显然,堆的效率比栈要低得多。

无论是堆还是栈,都要防止越界现象的发生。

2.不同段存放的内容

a.数据段中存放(.data、.bss):全局变量(初始化以及未初始化的)、静态变量(全局的和局部的、初始化的以及未初始化的)

b.代码段中存放(.text):全局只读变量(const)、字符串常量

c.堆中存放(heap):动态分配的区域

d.栈中存放(stack):局部变量(初始化以及未初始化的,但不包含静态变量)、局部只读变量(const)

3.不同类型的变量在内存中的位置

a.全局变量已初始化的位于.data数据段;未初始化的则位于.bss未初始化数据段。

b.静态(static)全局变量也在.data数据段。

c.局部变量 在栈上。静态局部变量,并不是在调用函数时分配,在函数返回时释放,而是像全局变量一样静态分配,在.data数据段,但它的作用域只在函数中起作用。

d.const修饰的全局变量在.rodata只读数据段(const变量在定义时必须初始化,所以没有所谓的未初始化const变量),只读数据段在和.text同一个Segment.

4.全局变量与局部变量初始化的区别

局部变量可以用类型相符的任意表达式来初始化,而全局变量只能用常量表达式初始化。如下:

double pi = 3.14 + 0.0016; 不管pi是全局变量还是局部变量,此句都合法。

double pi = acos(-1.0);若pi是局部变量,合法;若pi为全局变量,则非法。

程序开始运行时要用适当的值来初始化全局变量,所以初始值必须保存在编译生成的可执行文件中,因此初始值在编译时就要计算出来,然而上面第二种初始化的值必须在程序运行时调用acos函数才能得到,所以不能用来初始化全局变量。请注意区分编译时和运行时这两个概念。为了简化编译器的实现,C语言从语法上规定全局变量只能用常量表达式来初始化。
如果全局变量在定义时不初始化则初始值是0,如果局部变量在定义时不初始化则初始值是不确定的。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值