操作系统内存管理方式
Chap.1
如何将计算机上有限的物理内存分配给多个程序使用
- 地址空间不隔离
- 内存使用效率低
- 程序运行的地址不确定
由此引出了中间层:虚拟地址
分段:将一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空
- 解决了第一和第三个问题
粒度更小的内存分割和映射方法:分页——将地址空间人为等分为固定大小的页
内存共享
页错误:进程需要->硬件捕获->操作系统接管进程:从磁盘中读出数据+建立页之间的映射关系
CPU->MMU:virtual address
MMU->Physical Memory:physical address
Chap.6
装载的方式:动态装入-程序运行的局部性原理
动态装入的思想:程序用到哪个模块,就将哪个模块装入内存,如果不用就暂时不装入,存放在磁盘当中
覆盖装入
在现代嵌入式的内存受限环境下,这种方法具有一定的应用价值
覆盖管理器->组织成树状的调用依赖关系
调用路径:当某个模块被调用时,整个调用路径上的模块必须都在内存中,以确保模块执行完毕后能正确返回
禁止跨树间的调用:模块归并
覆盖装入,速度较慢
页映射
替换算法的选择:FIFO、LUR等
现在操作系统的存储管理器普遍采用这种方式
从操作系统角度看可执行文件的装载
进程建立
- 创立一独立的虚拟地址空间
- 分配页目录等映射函数所需的相应数据结构
- 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系
- VMA:虚拟内存区域
- 将CPU的指令寄存器设置成可执行文件的入口地址,启动运行
页错误
- 查询第二步中建立的数据结构
- 找到空页面所在的VMA
- 计算出相应的页面在可执行文件中的偏移
- 在物理内存中分配一相应页面
- 将进程中该虚拟页与分配的物理页之间建立映射关系
elf的空间进一步优化:segment概念的引入
对于相同权限的段,将其合并到一起当作一个段进行映射 所有相同属性的Section被归类到一个Segment,并且映射到同一个VMA
一个进程基本上可以分为4种VMA段
- 代码VMA,只读可执行,有映像
- 数据VMA,可读写、==可执行==,有映像
- 堆VMA,可读写、==可执行==,无映像,匿名向上扩展
- 栈VMA,可读写、==不可执行==,无映像,匿名向下扩展
查看可执行文件的Section: readelf -S [file] 查看Segment:readelf -l [file]
段地址对齐
导致各个段的虚拟地址往往不是系统页面长度的整数倍
计算:
现有VMA0的起始地址为0x08048000,长度为0x709e5,VMA1与VMA0的最后一个虚拟页面共享一个物理页面,页面大小为0x1000,映射两遍,则VMA1地址为________
进程栈的初始化
在Ubuntu17.04下,初始化之后的栈空间发生了变化
ELF和PE的装载
ELF
fork()->execve()->sys_execve()->do_execve()->load_elf_binary()
PE
计算
1