核心就是RAM和ROM的作用和区别
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
bss是英文Block Started by Symbol的简称。
bss段属于静态内存分配。
数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。
数据段属于静态内存分配。
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
一个程序本质上都是由 bss段、data段、text段三个组成的。
这样的概念,不知道最初来源于哪里的规定,但在当前的计算机程序设计中是很重要的一个基本概念。
而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。
在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;
而==bss段不在可执行文件中,由系统初始化,==全局的未初始化变量存在于.bss段中,具体体现为一个占位符;
全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间;.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);.data却需要占用,其内容由程序初始化。
bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小;
bss段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。
data段(已手动初始化的数据)则为数据分配空间,数据保存在目标文件中;data段包含经过初始化的全局变量以及它们的值。
包含data段和bss段的整个区段此时通常称为数据区。
包含两部分,即代码和数据
read-only data,只读的数据
Shows how many bytes are occupied by read-only data. This is in addition to the inline data included in the Code (inc. data) column. 除inline data 之外的所有只读数据。
read write data,可读写的数据
Shows how many bytes are occupied by read-write data.
zero initialized data,零初始化的可读写变量
Shows how many bytes are occupied by zero-initialized data.
keil编译器默认是把你没有初始化的变量都赋值一个0。初始化为零,或者未初始化的变量,都存储于这个区域。
存储Size:
RO size: Code + RO_data
RW size: RW_data + ZI_data
ROM (minimum)size = Code + RO_data + RW_data (即烧/下载程序到FLASH/ROM时,所占用的最小空间)
Total ROM Size (Code + RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。
RAM size: RW Data + ZI Data (即程序运行的时,RAM使用的空间)
linking...
Program Size: Code=30550 RO-data=762 RW-data=140 ZI-data=48436
Code, RO-data,RW-data ............flash
RW-data, ZIdata...................RAM
初始化时RW-data从flash拷贝到RAM
生成的map文件位于list文件夹下 (KEIL)
Total RO Size (Code + RO Data) 31312 ( 30.58kB)
Total RW Size (RW Data + ZI Data) 48576 ( 47.44kB)
Total ROM Size (Code + RO Data + RW Data) 31452 ( 30.71kB)
内存中供用户使用的存储空间分为代码区与数据区两个部分。
变量存储在数据区,数据区又可分为静态存储区与动态存储区。
静态存储是指在程序运行期间给变量分配固定存储空间的方式。如全局变量存放在静态存储区中,程序运行时分配空间,程序运行完释放。
动态存储是指在程序运行时根据实际需要动态分配存储空间的方式。如形式参数存放在动态存储区中,在函数调用时分配空间,调用完成释放。
对于静态存储方式的变量可在编译时初始化,默认初值为O或空字符。
对动态存储方式的变量如不赋初值,则它的值是一个不确定的值。
用于说明具有局部作用域的变量,它表示变量具有局部(自动)生成期,但由于它是所有局部作用域变量说明的缺省存储类指明符,所以使用得很 少。要注意的是,所有在函数内部定义的变量都是局部变量,函数内部定义的变量其作用域只在函数内部。它的生存期为该函数运行期间,一旦离开这个函数或这个 函数终止,局部变量也随之消失。
当声明了这个指明符后,编译程序将尽可能地为该变量分配CPU内部的寄存器作为变量的存储单元,以加快运行速度。注意,寄存器与存储器是 不同的。寄存器一般在CPU内部,而存储器一般指外部的(比如内存条),CPU内部的寄存器其运算速度是很高的。当寄存器已分配完毕,就自动地分配一个外 部的内存。它的作用等价于auto,也只能用于局部变量和函数的参量说明。
表示变量具有静态生成期。static变量的的特点是它离开了其作用域后,其值不会消失。(即内存一直被它占有,不会被释放)
一般用在工程文件中。在一个工程文件中因为有多个程序文件,当某一个变量在一个程序文件中定义了之后,如果在另一个程序文件中予以定义, 就会出现重复定义变量的错误。使用extern存储类型指明符就可以指出在该文件外部已经定义了这个变量。extern变量的作用域是整个程序。
动态数组和静态数组虽然在使用时看起来没有什么差别,但他们实现是不一样的。
反汇编看一下他们的代码。
数组类型 | C/C++代码 | 汇编实现 | 简略说明 |
---|---|---|---|
局部变量 | a[7] = 0; | MOV DWORD PTR SS:[EBP-C], 0 | 采用EBP在堆栈定位变量[EBP - 28] a[0] … [EBP - 4] a[9] |
静态局部变量 | s_a[7] = 0; | MOV DWORD PTR DS:[4C5E5C], 0 | 静态变量会被放到数据.data段中 |
全局变量 | g_a[7] = 0; | MOV DWORD PTR DS:[4C5E84], 0 | 全局变量和静态变量一样,会被放到数据.data段中 |
数组指针(malloc) | p1_a[7] = 0; | MOV EAX, DWORD PTR SS:[EBP-2C] MOV DWORD PTR DS:[EAX+1C], 0 | 对于数组指针,要进行两次寻址 0x1C / 4 = 7 |
数组指针(new) | p2_a[7] = 0; | MOV EAX, DWORD PTR SS:[EBP-30] MOV DWORD PTR DS:[EAX+1C], 0 | 同上 |
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
栈又称堆栈,是用户存放程序临时创建的局部变量,
也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。
从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。