内存分段
为什么分段
为什么把程序的指令和数据分成多段?
-
共享指令,节省空间**(最重要)**
运行多个程序时,指令可以只保存一份。与数据区分开来,实现指令共享,节省资源。
-
保护只读区域:防止程序的指令无意的修改。
-
提高cpu缓存命中率:
- 现代CPU的缓存一般分为 指令缓存和数据缓存
- 提高程序的局部性,从而提高cup缓存命中率。
x86_63 内存布局
由于 C/C++ 编译的程序占用的 x86_63 内存布局
编译后
编译后的可执行文件中,有 .text
.rodata
data
.text
代码区.rodata
只读数据段。- const变量
- 虚函数表
- 编译期编译器确定虚函数表
- 虚函数表属于类,类的所有对象共享这个类的虚函数表
.data
数据段。已经初始化的静态变量 (全局静态变量和局部静态变量)
在暂时没有 .bss
堆
内存映射段
栈
内核空间
-
.bss
——由于运行时会全部初始化为 0 出于节省空间就不再指定了 -
没有
堆 栈
运行时才分配。 -
没有 内核空间 内存映射段 操作系统运行时分配。
运行时 虚拟内存分段
运行时的内存模型(也就是虚拟内存),本质上:
.text
代码区.rodata
只读数据段 —— const变量,虚函数表.data
数据段。已经初始化的静态变量 (全局静态变量和局部静态变量)
上述
.text
.rodata
data
在编译期就存在。
.bss
数据段。未初始化的静态变量,默认全是0
以上和程序的生命周期相同。
text程序加载时被分配,程序结束后释放。
全局变量构造函数在main()函数执行前执行。
main()函数执行结束,C++运行库释放全局变量,静态变量。
-
heap
堆。生命周期:- 运行时手动分配和释放。程序员管理 new delete new[] delete[]
- 进程结束时,操作系统释放。
-
内存映射段。文件映射,动态库,匿名映射。
-
stack
栈。- 函数参数值,局部变量值 etc
- 生命周期:离开作用域后系统自动释放。编译器自动分配释放。
-
PCB 进程控制块
包含进程信息(控制信息等)内核空间,用于操作系统管理。