ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

堆栈,数据,文本,heap,bss,text data,stack

2021-12-21 06:31:09  阅读:207  来源: 互联网

标签:初始化 变量 text bss SRAM 全局变量 data stack


堆栈,数据,文本,heap,bss,text data,stack

text data bss stack heap 段

根据APUE,程序分为下面的段:.text, data (initialized), bss, stack, heap。
data/bss/text: 
text段在内存中被映射为只读,但.data和.bss是可写的。
bss是英文Block Started by Symbol的简称,通常是指用来存放程序中未初始化的全局变量的一块内存区域,在程序载入时由内核清0。BSS段属于静态内存分配。初始值也是由用户自己定义的连接定位文件所确定,用户应该将定义在可读写的RAM区内,源程序中使用malloc分配的内存就是这一块,不是根据data大小确定,主要由程序中同时分配内存最大值所确定,不过如果超出了范围,也就是分配失败,可以等空间释放之后再分配。
text段是程序代码段,在AT91库中是表示程序段的大小,是由编译器在编译连接时自动计算的,当你在链接定位文件中将该符号放置在代码段后,那么该符号表示的值就是代码段大小,编译连接时,该符号所代表的值会自动代入到源程序中。
data包含静态初始化的数据,所以有初值的全局变量和static变量在data区。段的起始位置也是由连接定位文件所确定,大小在编译连接时自动分配,与程序大小没有关系,但和程序使用到的全局变量,常量数量相关。
stack/heap:
栈(stack)保存函数的局部变量和参数。是一种“后进先出”(Last In First Out,LIFO)的数据结构,这意味着最后放到栈上的数据,将会是第一个从栈上移走的数据。对于哪些暂时存贮的信息,和不需要长时间保存的信息来说,LIFO这种数据结构非常理想。在调用函数或过程后,系统通常会清除栈上保存的局部变量、函数调用信息及其它的信息。栈另外一个重要的特征是,地址空间“向下减少”,即当栈上保存的数据越多,栈的地址就越低。栈(stack)的顶部在可读写的RAM区的最后。

堆(heap)保存函数内部动态分配内存,是另外一种用来保存程序信息的数据结构,更准确的说是保存程序的动态变量。堆是“先进先出”(First In first Out,FIFO)数据结构。只允许在堆的一端插入数据,在另一端移走数据。堆的地址空间“向上增加”,即当堆上保存的数据越多,堆的地址就越高。

在程序中的存储详情如下:

char *string = "Hello World";
int iSize;

char *fun(void)

{
     char *p;
     iSize = 8;
     p = malloc(iSize);
     return p;
}

存放的位置

Text:上面标记为红色的部分(还包括整个fun函数,由于下边需要,所以没有标记)都存放在Text段,Text段用来存放代码(二进制文件)和常量,该段的数据通常是只读的

例:

Text:上面标记为红色的部分(还包括整个fun函数,由于下边需要,所以没有标记)都存放在Text段,Text段用来存放代码(二进制文件)和常量,该段的数据通常是只读的

例:

  1. char *p = "Hello";
  2.  
  3. p[0] = 'a';

 VC6.0下,编译无错,但运行是提示内存不可写,这就是因为"Hello"存放在Text段,是只读的,你不能去修改.

Data: 已经初始化了的全局变量string就存放在该段,Data段用来存放初始化了的变量,即初始化了的全局变量和静态变量

BSS: 未初始化的全局变量iSize存放在这,BSS段主要存放在未初始化的变量,即未初始化的全局变量和静态变量

Heap: 程序员手动分配的malloc(iSize)这篇内存存放在该段,也需要用户自行释放

Stack:函数里的局部变量*p存放在该段,Stack段主要存放局部变量、临时变量、函数相互调用的返回的地址,该段由编译器自行分配和释放

接下来来看看,什么被分配了内存,什么时候释放内存:

全局变量和静态变量:程序开始的时候就分配了,程序结束时候释放内存。

局部变量:函数调用的时候为变量分配内存,调用结束释放内存。

堆里的:调用malloc时分配内存,调用free时释放。

.text .data .bss .stack .heap 详解

.text 代码段:用来存放代码和常量(const 关键字定义的变量)。

.data 数据段:用来存放有初始值的全局变量、全部静态变量(static 关键字定义的变量)。注意全部静态变量包括全局静态变量和局部静态变量,并且不论这些变量是否有初始值。即不管有没有初始值,也不管是全局变量还是定义在函数内的局部变量,只要是用 static 关键字定义的变量,都放在 .data 数据段内。

.bss BSS段:用来存放没有初始值的全局变量。(没有初始值的局部变量好像也存在这里,网上验证帖子,待验证)。

.stack 栈区: 用来存放局部变量,函数的参数,返回值等,由编译器自动分配释放。如一个函数被调用后,产生的临时变量都会存到栈区的顶部,当函数完成后,会自动从顶部将刚使用的数据销毁。栈区的地址是从高地址向下增长的。

.heap 堆区:  用来动态内存分配,如 malloc, new 申请的内存,由程序员手动分配释放。程序中不释放,则程序结束时,由OS回收;据说这个和数据结构中的堆 没有什么关系;堆区使用时地址向上增长。

以上5段,在生成的 hex 文件中是怎么分配呢?

Hex 文件分为三部分(可通过 map 文件查看到)

.text 代码段

  1. .data 数据段

 

 

 .bss, .stack, .heap的位置信息(即起始位置和大小)

 

 

 程序运行时,这5段各起什么作用,又在物理存储空间哪个位置?

现在的计算机架构主要有两种:

  1. 冯诺依曼架构:必须从 RAM 中取出执行代码,即执行代码要先存入 RAM 中。
  2. 哈佛架构:可以直接从 flash 执行代码。

ARM 架构是哈佛架构,可以直接从 flash 取指令执行,所以在程序运行期间:

.text 段位于 flash 内,具体位置和 hex 文件中 .text 段的位置一致,程序运行时直接从 flash 内读取指令并执行。.text 段都是代码和常量,只读,所以可以放在 flash 内。

 .data 段在MCU启动过程中,会被从 flash 内 copy 到 SRAM 内(各家的启动代码都会做此操作)。程序运行时是操作 SRAM 中的变量。 .data 段内都是变量,可读可写,所以会被放在 SRAM 内。所以 .data 段有两个地址,一个是在 flash 内的地址,flash 内放的就是变量的初始值;另一个是在 SRAM 内的地址,SRAM 内的地址就是程序运行时变量所在的位置。一个变量初始化的过程,就是启动代码将 .data 段从 flash 内 copy 到 SRAM 中的过程,因此 SRAM 中的 .data 区域,在程序运行时(MCU 启动代码运行之后)一开始就有值了。这也解释了,为什么 static 变量的初始化只执行一次(即在编译时初始化),注意这种通过启动代码 copy flash 中内容到对应 SRAM 中的所谓在编译时初始化,和函数内部局部变量是通过用户代码初始化是不一样的操作,局部变量通过用户代码初始化后面会详细讲解。另外要注意,.data 段内数据分有初始值的全局变量和 static 变量两块,这两块变量虽然都在 .data 段,但作用域不同,全局变量是全局作用域,而 static 变量是局部作用域。

.bss, .stack 和 .heap 段在 hex 文件内有对应的起始位置和大小信息,MCU 在启动时(启动代码)会根据这些信息配置 SRAM,给这三段在 SRAM 中按 hex 文件中的信息分配好对应的位置和大小。程序运行期间,对这三段的操作都是在 SRAM 中进行的。注意 .bss 要初始化,一般是启动代码会做这个操作,将整个 .bss 段初始化为 0 (可参考bss段为什么要初始化)。

总结一下这5段在物理存储器上的位置及占用大小:

Flash 占用大小 =  .text 大小 + .data大小 + 其它section(如.bss, .stack, .heap等) 位置信息大小

SRAM 占用大小 = .data 大小 + .bss 大小 + .stack大小 + .heap大小

程序运行时,这 5 段在物理存储器上的位置如下图

 

 

 下面用一段代码来详细介绍上面这5段

 

 

 各变量所在位置如上图注释,下面把一些重点概念,如函数中的局部变量如何赋值,用此代码讲解一下:

在编译时初始化和函数内局部变量用户代码初始化

如下图

 

 

 全局变量 a 和 静态变量 e 是在编译时初始化:这两个变量都在 .data 段,MCU 启动时,启动代码会将 .data 段从 flash copy 到 SRAM ,copy 操作完成后, SRAM  .data 段中的变量就都已经有了初始值(之前存在 flash 中的初始值)。本例中的变量 a 和 c 就是在这个过程中完成的初始化。这个初始化过程中,不需要调用任何用户代码,所以被称作在编译时初始化。注意:编译时初始化只初始化一次。因为是启动代码执行 copy 操作完成的初始化,启动代码只执行一次,所以这个初始化的操作也就只会执行一次。

局部变量 g 在 .stack 中,也就是说,只有在程序运行时,并在调用 main 函数时,才会在 SRAM 的 stack 区域内给变量 g 开出一个空间,让程序可以对 g 进行操作。那如何对变量 g 赋初始值 2 的呢?是执行 g = 2; 这段代码,g =2; 这段代码在 .text 中(存在 flash 中),每次调用 fun 函数时都会调用 g = 2; 这段代码,这段代码会给在 stack 中的变量 g 赋初始值 2。但和编译时初始化不同,每次调用 fun 函数,都会重新对变量 g 做赋值操作,即函数被调用几次,函数内局部变量的初始化操作就会执行几次。所以用户代码初始化函数内局部变量会初始化多次。

函数内局部变量初始化和函数内静态变量初始化的区别

 

 

 局部变量 g 的初始化上面已详细讲解。

局部静态变量 y 的初始化和 g 不同,静态变量 y 是在 .data 段中,和全局变量 a 一样,是用在编译时初始化的方法完成初始化的。详细过程参考上面关于变量 a 的初始化过程。

注意:这样 g 和 y 在初始化值方面的用法就完全不同了。在 fun 函数每次被调用时, g 都被初始化为2,而 y 则不是一直是 3,y 的值是上次 fun 被调用时 y 被赋的值(类似静态变量 y 使用的实例参考本链接)。

用 g 和 y 在 SRAM 中的位置也可以解释不同:g 处于 SRAM 的 stack 区域,只有 fun 函数被调用时才给 g 分配空间,并且每次分配后,都会对 g 赋初始值 2,所以每次调用 fun 函数,g 初始值都是2,并且函数 fun 执行完后下一句指令(pull)会自动注销 g 在 stack 中的空间;而 y 处于 SRAM 的 .data 区域,y 在 SRAM中有一个固定的物理空间,即使 fun 函数执行完毕,y 在 SRAM 中还是有一个空间保留着 y 的值,static int y = 3; 这句其实和定义全局变量初始值一样,只是在编译时将 y 放在了 .data段,并在 flash 中保存了其初始值 3, 这样在 MCU 启动时完成了对 y 的初始化,y 也就只在这时等于 3,之后 fun 执行中只要改变了 y 的值,下次再调用 fun 时,y 中还是上次的值,y=3; 这句代码完全不会执行。

static 变量详细介绍和使用可查看本链接。

对于常量

 

 

 c 位置在 .text 段,程序运行期间 c 是在 flash 内,即程序要用到 c 时会去 flash 的 c 地址处直接取值。和全局变量 a 不同,启动代码不会 copy c 到 SRAM 中,SRAM 中不会有 c 的位置。

Code, RO, RW, ZI 

这些只是用 keil 编译器时,对 .text, .data, .bss, .statck, .heap 这 5 段的不同称呼,详细介绍可参考本链接。简单总结如下:

Code:代码的大小

RO:常量所占空间

RW:程序中已经初始化的变量所占空间

ZI:未初始化的static和全局变量以及堆栈所占的空间

Flash占用大小=Code+RO+RW

SRAM占用大小=RW+ZI

 

参考链接:

https://blog.csdn.net/phenixyf/article/details/116718762

https://blog.csdn.net/lwbeyond/article/details/7275561#

标签:初始化,变量,text,bss,SRAM,全局变量,data,stack
来源: https://www.cnblogs.com/wujianming-110117/p/15713655.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有