近日在解决一个编译问题时,仍然在考虑一个问题,那就是Linux下可执行程序执行时显存是哪些状态,是根据哪些方法分配显存并执行的。
linux下显存管理是通过虚存管理的,在分配显存时并不是在数学显存开辟了一段空间,而是在使用时才分配的。而且是通过段页式管理。
linux下显存分配是以页为单位的。而页是通过段管理。各个段之间是独立的,便捷管理。linux程序执行时才能分为下边几个显存段:
text、rodata、data、bss、stack、heap。
一、各显存区段的介绍
系统内的程序分为程序段和数据段,具体又可细分为一下几个部份:
(1)text段-代码段
text段储存程序代码,运行前就早已确定(编译时确定)linux游戏,一般为只读,可以直接在ROM或Flash中执行,无需加载到RAM。
在嵌入式开发中,有时为了非常的需求(比如加速),也可将某个模块搬动到RAM中执行。
(2)rodata段(read-only-data)-常量区
rodata段储存常量数据,例如程序中定义为const的全局变量,#define定义的常量,以及例如“HelloWorld”的字符串常量。只读数据,储存在ROM中。
注意:有些立刻数与指令编译在一起,置于text段。
const修饰的全局变量在常量区。const修饰的局部变量只是为了避免更改,没有倒入常量区。
编译器会除去重复的字符串常量,程序的每位字符串常量只有一份。
有些系统中rodata段是多个进程共享的,目的是为了提升空间借助率。
(3)data段
data储存早已初始化的全局变量,属于静态显存分配。(注意:初始化为0的全局变量还是被保存在BSS段)
static申明的变量也储存在数据段。
链接时年率加入执行文件。执行时,由于这种变量的值是可以被改变的,所以执行时期必须将其从ROM或Flash搬动到RAM。反正,data段会被加入ROM,但却要轮询到RAM的地址。
(4)bss段
bss段储存没有终值的全局变量或默认为0的全局变量,属于静态显存分配。
bss段不抢占执行文件空间(无需加入程序之中,只要链接时将其轮询到RAM即可),但抢占程序运行时的显存空间。
执行期间必须将bss段内容全部设为0。
(5)stack段-栈
stack段储存参数变量和局部变量,由系统进行申请和释放,属于静态显存分配。
stack的特征是先进先出,可用于保存/恢复调用现场。
栈的概念来自数据结构,栈只能在一端操作,所以先入栈的后出。
“先进后出”,这些结构保护之前的现场,如一个函数被调用后,形成的临时变量就会存到栈区的底部,当函数完成后,会手动从底部将刚使用的数据销毁。另外栈区的地址是从高地址向上下降的。
(6)heap-堆
heap段是程序运行过程中动态分配的显存段,由用户申请和释放(比如malloc和free)。
申请时起码分配虚存,当真正储存数据时才分配化学显存。释放时也不是立刻释放化学显存,而是可能被重复借助。
堆区,拿来动态显存分配,如malloc,new申请的显存,由程序员分配释放。
程序中不释放,则程序结束时,由OS回收。听说这个和数据结构中的堆没有哪些关系。堆区使用时地址向下下降。
程序在执行时,会形成临时变量或是函数返回值,还有函数中动态分配的地址空间,如malloc,new等…
按照这种需求,才须要堆和栈的出现,所以堆(heap)和栈(Stack)这两个段是在程序运行时才有.
二、总结
1、执行文件中包含了text、rodata、data段的内容linux系统,不包含bss段内容(一堆0装入执行文件没有意义)。
2、程序被储存的地址和执行时期的地址不一定一致。
LMA(loadmemoryaddress):某程序区被储存的地址。
VMA(virtualmemoryaddress):程序区段在执行时期的地址。
比如data段会被储存在ROM,但执行时必须加载到RAM,则在ROM中的地址就称为LMA,在RAM中的地址就是VMA。
3、堆和栈的显存下降方向是相反的:栈是从高地址向低地址生长,堆是从低地址向高地址生长。
4、局部变量储存在stack中,编撰函数时要注意假如该函数被递归调用好多次linux系统内存管理,可能会造成stackoverflow的问题。
(尤其在嵌入式开发中,显存资源有限,所有显存几乎就会被塞满,stackoverflow和stackunserflow都极可能造成很大问题)
执行过程:
代码区的指令依次执行。代码由操作码和操作数组成,操作码决定是次序执行,还是跳转,还是循环等。
操作数可能是立刻数,即具体的数直接包含在代码中,或则是局部变量,则在栈区分配空间,之后引用该数据地址执行linux系统内存管理,或则是BSS,DATA段的数据,同样引用其地址执行。
正由于代码有不同的操作,所以程序在显存中执行时,才分成不同的区,便于节省空间或访问便捷。
对于全局变量和静态变量,通常不会修改其值,但整个执行过程都须要访问,就单独放在一个区进行管理。
临时变量生命周期短,须要频繁的操作,则统一放在栈区。用户自由分配使用的空间统一置于堆区,以便管理。