预备知识
在区分一个程序的堆栈、bss、text段、RO、RW、ZI等概念时,首先区分一下程序进程和程序文件,然后了解一下哈弗结构和冯诺依曼结构。程序进程就是程序运行时的程序,程序文件是编译后生成的可执行文件,比如.bin文件等。哈佛结构和冯诺依曼结构的主要区别就是处理器能不能实现取指令和取数据的并发进行。嵌入式芯片中主要是哈佛结构,PC机上是冯诺依曼结构。
哈佛结构
经典的哈佛结构
:程序存储器和数据存储器是各自独立的存储器。处理器应该有两套总线,一套是程序存储器的数据和地址总线,一套是数据存储器的数据和地址总线。取指令和取数据能并发进行。51的程序进程的逻辑代码段放在ROM中,而变量部分则放在RAM中,取ROM中的指令和RAM中的变量是两套总线。
改进型哈佛结构
:程序存储器和数据存储器是各自独立的存储器。处理器只有一套总线,分时访问程序存储器和数据存储器,但是在处理器中有icache和dcache将程序和数据分开,所以处理器仍然可以并步执行取指令和取数据。从ARM9开始以后所有的ARM处理器内核都是改进型的哈佛结构。ARM的逻辑代码和变量都是存放在RAM中的,但是,它在内存中划分了两部分的空间,其中一部分放逻辑代码,另一部分存放变量,之间不会相互干扰。
冯诺依曼结构
冯诺依曼结构
:没有程序存储空间和数据存储空间之分。处理器只有一套总线,取指令和取数据是不能同时进行的。程序进程全部在RAM中,他们之间一般是按照代码的执行顺序依次存储。由于全部在RAM中,运行速度快,所需的RAM多。
一、内存分区
多任务操作系统中的每一个进程都运行在都运行在一个属于自己的虚拟空间,在32位模式下,它总是一个4GB的内存地址块。这些虚拟地址通过页表(page table)映射到物理地址。一部分虚拟地址需要给内核使用,具体分布与操作系统有关。
为什么要使用虚拟地址,可参考链接: https://www.cnblogs.com/zhuangquan/p/12157266.html
语言层面
C/C++五大内存分区(内存由低到高)
:
1、代码区:存放程序的二进制代码,内存由系统管理
2、常量区:存放字符串常量与const修饰的常量,常量区的内存是只读的,程序结束后由系统释放
3、静态存储区:存放全局变量和静态变量(包括静态全局变量与静态局部变量),初始化的全局变量和静态局部变量放在一块,未初始化的放在另一块。
4、堆区(heap):该区由程序员申请后使用,需要手动释放否则会造成内存泄漏。如果程序员没有手动释放,那么程序结束时可能由OS回收
5、栈区(stack):存放函数形参和局部变量(auto类型),由编译器自动分配和释放,
分区 | 存储类型 |
---|---|
代码区 | 可执行程序代码 |
常量区 | 字符串常量与const修饰的常量 |
静态存储区 | 全局变量和静态变量 |
堆区(heap) | 该区由程序员申请后使用 |
栈区(stack) | 存放函数形参和局部变量 |
CPU层面
对于CPU来说程序在内存中的分区定义略有不同,总体上来说大同小异,一个程序在内存中的分区可分:
1、text segment(代码段):包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码。
2、data segment(数据段):存储程序中已初始化的全局变量和静态变量
3、bss segment:存储未初始化的全局变量和静态变量(局部+全局),以及所有被初始化为0的全局变量和静态变量,对于未初始化的全局变量和静态变量,程序运行main之前时会统一清零。即未初始化的全局变量编译器会初始化为0
4、heap(堆): 当进程未调用malloc时是没有堆段的,只有调用malloc时采用分配一个堆,并且在程序运行过程中可以动态增加堆大小(移动break指针),从低地址向高地址增长。分配小内存时使用该区域。 堆的起始地址由mm_struct结构体中的start_brk标识,结束地址由brk标识。
5、stack(栈):使用栈空间存储函数的返回地址、参数、局部变量、返回值,从高地址向低地址增长。
分区 | 存储类型 |
---|---|
text | 可执行程序代码 |
data | const修饰的常量、初始化的全局变量和静态变量 |
bss | 未初始化或初始化为0的全局变量和静态变量 |
heap | 该区由程序员申请后使用 |
stack | 存放函数形参和局部变量 |
二、文件分区
一个可执行的程序文件可分为三部分:text 、data、bss。这三部分是在编译时就确定分配的空间,属于静态空间,所以被包含在可执行文件里;其余动态空间(局部变量,new分配的空间)在程序执行时分配,所以不包含在可执行文件里。
1、text segment(代码段):用来存放代码,一般是只读的区域;
2、data segment(数据段):用来存放const修饰的常量、初始化的全局变量、静态变量,只初始化一次。data又可分为RO-data(const修饰的常量)和RW-data(初始化的全局变量、静态变量);
3、bss segment:bss又叫ZI-data,用来存放未初始化的全局变量和静态变量,以及所有被初始化为0的全局变量和静态变量,对于未初始化的全局变量和静态变量,程序运行main之前时会统一清零。
分区 | 存储类型 |
---|---|
text | 代码 |
data | const修饰的常量、初始化的全局变量和静态变量 |
bss | 未初始化或初始化为0的全局变量和静态变量 |
本文参考:
https://blog.csdn.net/zdy0_2004/article/details/42296109
https://blog.csdn.net/dfl448866/article/details/90444228