C和C++内存模型

转载 2015年07月08日 08:58:30

C分为四个区:堆,栈,静态全局变量区,常量区
c++分为四个区:堆,栈,静态全局变量去,常量区,自由存储区。
 

根据c/c++对象生命周期不同,c/c++的内存模型有三种不同的内存区域,即自由存储区,动态区、静态区。
自由存储区:局部非静态变量的存储区域,即平常所说的栈
动态区: 用operator new ,malloc分配的内存,即平常所说的堆
静态区:全局变量 静态变量 字符串常量存在位置
而代码虽然占内存,但不属于c/c++内存模型的一部分

 

在linux系统中,程序在内存中的分布如下所示:

 

低地址 .text .data .bss

heap(堆)    

-->

unused   

<--

stack

(栈)      

env 高地址

其中 :

.text 部分是编译后程序的主体,也就是程序的机器指令。

.data 和 .bss 保存了程序的全局变量,.data保存有初始化的全局变量,.bss保存只有声明没有初始化的全局变量。

heap(堆)中保存程序中动态分配的内存,比如C的malloc申请的内存,或者C++中new申请的内存。堆向高地址方向增长。

stack(栈)用来进行函数调用,保存函数参数,临时变量,返回地址等。

是“Block Started by Symbol”的缩写,意为“以符号开始的块”。

  BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的 “text”段和包含已初始化数据的“data”段。BSS段的变量只有名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块” 指的是编译器处理未初始化数据的地方。BSS节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序 的二进制映象文件中并不存在。

  在采用段式内存管理的架构中(比如intel的80x86系统),bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

  比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。

  text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系 统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。

各个段的关系


图3-1所示为可执行代码存储时结构和运行时结构的对照图。一个正在运行着的C编译程序占用的内存分为代码区、初始化数据区、未初始化数据区、堆区 和栈区5个部分。

(点击查看大图)图3-1 C程序的内存布局

(1)代码区(text segment)。代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),如果反复,则需要使用跳转指令,如果进行递归,则需 要借助栈来实现。

代码区的指令中包括操作码和要操作的对象(或对象地址引用)。如果是立即数(即具体的数值,如5),将直接包含在代码中;如果是局部数据,将在栈区 分配空间,然后引用该数据地址;如果是BSS区和数据区,在代码中同样将引用该数据地址。

(2)全局初始化数据区/静态数据区(Data Segment)。只初始化一次。

(3)未初始化数据区(BSS)。在运行时改变其值。

(4)栈区(stack)。由编译器自动分配释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。每当一个函数被调用,该函 数返回地址和一些关于调用的信息,比如某些寄存器的内容,被存储到栈区。然后这个被调用的函数再为它的自动变量和临时变量在栈区上分配空间,这就是C实现 函数递归调用的方法。每执行一次递归函数调用,一个新的栈框架就会被使用,这样这个新实例栈里的变量就不会和该函数的另一个实例栈里面的变量混淆。

(5)堆区(heap)。用于动态内存分配。堆在内存中位于bss区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时有可能由OS 回收。

之所以分成这么多个区域,主要基于以下考虑:

一个进程在运行过程中,代码是根据流程依次执行的,只需要访问一次,当然跳转和递归有可能使代码执行多次,而数据一般都需要访问多次,因此单独开辟 空间以方便访问和节约空间。

临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。

全局数据和静态数据有可能在整个程序执行过程中都需要访问,因此单独存储管理。

堆区由用户自由分配,以便管理。

下面通过一段简单的代码来查看C程序执行时的内存分配情况。相关数据在运行时的位置如注释所述。

//main.cpp 
int a = 0;    //a在全局已初始化数据区 
char *p1;    //p1在BSS区(未初始化全局变量) 
main() 
{
int b;    //b在栈区
char s[] = "abc"; //s为数组变量,存储在栈区,
//"abc"为字符串常量,存储在已初始化数据区
char *p1,p2;  //p1、p2在栈区
char *p3 = "123456"; //123456\0在已初始化数据区,p3在栈区 
static int c =0;  //C为全局(静态)数据,存在于已初始化数据区
//另外,静态数据会自动初始化
p1 = (char *)malloc(10);//分配得来的10个字节的区域在堆区
p2 = (char *)malloc(20);//分配得来的20个字节的区域在堆区
free(p1);
free(p2);
}

相关文章推荐

C例子:程序内存模型

  • 2016-03-27 18:40
  • 795B
  • 下载

c++内存模型

  • 2015-10-10 10:08
  • 23.45MB
  • 下载

linux c内存模型

SECTIONS { ... secname start BLOCK(align) (NOLOAD) : AT ( ldadr )   { contents } >region :phdr =f...

C++类对象内存模型与成员函数调用分析(中)

2.4 虚拟成员函数这是本文中最复杂也最有趣的话题了。虚拟函数也是和继承这个话题相伴相生,所以本节将纳入对单继承、多重继承和虚拟继承,一起描述他们之间的关系,这样,对C++对虚拟函数的调用,以及由此所...

C++内存模型和名称空间总结

C++鼓励在开发程序时使用多个文件,一种有效的组织策略是:使用头文件来定义用户类型,为操纵用户类型的函数提供函数原型;并将函数定义放在一个独立的源代码文件中。头文件和源代码文件一起定义和实现了用户定义...

C++继承与Class 内存模型

C++类主要包括属性和操作两类,在对象模型中即一个对象实例中占用内存的只是Class的属性部分,也就是数据成员部分,本文旨在剖析C++对象模型中在有继承情形下类对象的内存布局,主要分4种情况讨论:单一...

从内存模型角度来看C++多态实现机制

最近对多态的实现机制比较感兴趣,本文从C++内存模型角度去看待多态的实现机制。实例如下: #include #include #include using namespace std; clas...

探索C++内存模型(下)

在上一节中,主要针对无函数覆盖的类继承情况进行分析,接下来将在前一节的基础上,讨论带有函数覆盖的各种继承下C++类的内存模型。如果有疑问,欢迎及时沟通讨论! 运行环境:Ubuntu 16.04 LT...

深入理解C++对象模型-对象的内存布局,vptr,vtable

vtpr的位置: 为了支持多态,C++引入了vtpr和vtable这两个概念.对于每个有虚函数的类,C++都会为其生成一个vtable,并在类中添加一个隐含的数据成员vptr. 对于vptr在对象中...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)