2017-2018-1 20155321 《信息安全系统设计基础》第十一周学习总结
教材学习内容总结
虚拟存储器
定义
对主存的抽象机制,是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互。
功能
- 将主存看成是一个存储在磁盘上的地址空间的高速缓存,在内存中只保存活动区域,并根据需要在磁盘和内存之间来回传送数据。
- 为进程提供了一致的地址空间,从而简化了存储器管理。
- 保护了每个进程的地址空间不被其他进程所破坏。
物理和虚拟地址
CPU通过生成一个虚拟地址(Virtual address,VA)来访问主存。将虚拟地址转换为物理地址叫做地址翻译(address translation)。地址翻译也需要CPU硬件和操作系统之间的紧密结合。
CPU芯片上有叫做存储器管理单元(Memory Management Unit,MMU)的专用硬件。利用存储在主存中的查询表来动态翻译虚拟地址。 查询表由操作系统管理。
虚拟存储器作为缓存的工具
概念上而言,虚拟存储器(VM)被组织为一个存放在磁盘上的N个连续字节大小的单元组成的数组。每个字节都有一个唯一的虚拟地址,这个唯一的虚拟地址作为到数组的索引。磁盘上数组的内容被缓存到主存中。VM系统通过将虚拟存储器分割为称为虚拟页的大小固定的块来处理磁盘和主存信息交互问题。
任何时候,虚拟页的集合都被分为3个不相交的子集。
1、[未分配的] VM系统还未分配(或者创建)的页。未分配的块没有任何数据与之相关联。不占用磁盘空间
2、[缓存的] 当前缓存在物理存储器的已分配页。
3、[未缓存的] 没有缓存在物理页面存储器中的已分配页。
页表
虚拟存储器作为存储器管理的工具
操作系统为每个进程提供一个独立的页表,VM简化了链接和加载,代码和数据共享,以及应用程序的存储器分配。
1.简化链接
独立的空间地址意味着每个进程的存储器映像使用相同的格式。文本节总是从0x08048000(32位)处
或0x400000(64位)处开始。然后是数据,bss节,栈。一致性极大简化了链接器的设计和实现。
2.简化加载
在ELF可执行文件中.text和.data节是连续的。要把这些节加载到一个新创建的进程中,linux加载器.
分配虚拟页的一个连续的片,从地址0x08048000处(32bit)开始, 或者从0x400000(64bit),
[把这些虚拟页标记为无效,将页表条目指向目标文件中适当的位置,加载器从不实际拷贝任何数据从磁盘到存储器.]
3.简化共享
4.简化存储器分配
malloc在堆空间分配一个适当数字(例如k)个连续的虚拟存储器页面,并且将他们映射到物理存储器中任意
位置的k个任意(不一定连续)的物理页面。
虚拟存储器作为存储器保护的工具
Linux虚拟存储器系统
内核虚拟存储器包含内核中的代码和数据。
1、内核虚拟存储器的某些区域被映射到所有进程共享的物理页面.如:内核代码,全局数据结构。
2、Linux将一组连续的虚拟页面(大小等同于系统DRAM总量)映射到相应的一组物理页面。[直接映射,不使用页表]
3、内核虚拟存储器包含每个进程不相同的数据。页表,内核在进程上下文中时使用的栈等。
虚拟存储器区域的内核数据结构
task_struct
mm_struct: 描述了虚拟存储器的当前状态。
pgd: 指向第一级页表的基址。当进程运行时,内核将pgd存放在CR3控制寄存器
mmap: 指向vm_area_structs的链表
vm_area_structs描述了当前虚拟地址空间的一个区域(area).
vm_start:指向这个区域的起始处。
vm_end:指向这个区域的结束处。
vm_port:描述这个区域内包含的所有页的读写许可权限。
vm_flags:描述这个区域页面是否与其他进程共享,还是私有等
vm_next: 指向链表的下一个区域。
存储器映射
定义
Linux 通过将一个虚拟存储器区域与一个磁盘上的对象关联,以初始化这个虚拟存储器区域的内容。
虚拟存储器区域可以映射到以下两种类型文件:
1、Unix文件系统中的普通文件:一个区域可以映射到一个普通磁盘文件的连续部分。
例如,一个可执行文件。文件区(section)被分成页大小的片,每一片包含一个虚拟页面的初始化内容。
仅仅是初始化,虚拟页面此时还并未进入物理存储器,直到CPU第一次引用这个页面。
2、匿名文件
匿名文件由内核创建,包含的全是二进制零。CPU第一次引用这样区域(匿名文件)的虚拟页面时,
将存储器中牺牲页面全部用二进制零覆盖。并将虚拟页面标记为驻留在存储器中。
注意在磁盘和存储器之间并没有实际的数据传送。又叫请求二进制零的页(demand-zero page)。
注意: 一个虚拟页被初始化了,它就在一个有内核维护的专门的交换文件(交换空间)之间切换。
在任何时刻,交换空间都限制着当前运行着的进程能够分配的虚拟页面的总数。
再看共享对象
一个对象可以被映像到虚拟存储器的一个区域,要么作为共享对象,要么作为私有对象.
私有对象的写时拷贝
再看fork函数
当fork函数被当前进程调用时:
1、内核为新进程创建内核数据结构,并分配给它唯一一个PID。
2、为了给新进程创建虚拟存储器[创建页目录]。
3、创建了当前进程的mm_struct,区域结构和页表的原样拷贝。
4、将两个进程的每个页面都标记为[只读]。并给两个区域进程的每个区域结构都标记为[私有的写时拷贝]。
注意:[没有对物理存储器进行拷贝,利用的是私有对象的写时拷贝技术。]
使用mmap函数的用户级存储器映射
Unix进程可以使用mmap函数来创建新的虚拟存储器区域,并将对象映射到这些区域中
#include <unistd.h>
#include <sys/mman.h>
void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset);
返回:若成功时则为指向映射区域的指正,若出错则为MAP_FAILED(-1).
munmap函数删除虚拟存储器的区域
#include
void *munmap(void *start,size_t length);
返回:若成功则为0,若出错则为-1
教材学习中的问题和解决过程
1.mmap为什么比传统的读写速度要快
mmap : 将文件内容直接映射到进程的地址空间,通过对这段内存的读写,来达到对文件的读写目的;
read,write : 每次调用都需要从用户态到内核态的切换,且数据需要从用户态拷贝到内核态,然后再写入磁盘,增加了中间步骤
mmap的缺点 : 不能改变文件长度,无法写入多余的字符。
2.如何调用execve函数
假设运行在当前的进程中的程序执行了如下的调用:
execve("a.out",NULL,NULL);
加载并运行需要以下几个步骤
1、删除已存在的用户区域:删除当前进程虚拟地址的用户部分中已存在的区域结构。
2、映射私有区域:为新程序的文本,数据,bss和栈区域创建新的区域结构。所有新的区域结构都是私有的,写时拷贝的。
文本和数据区域被映射到a.out文件中的文件和数据区。bss区域是请求二进制零,映射到匿名文件。
3、映射共享区域
4、设置程序计数器
5、execve最后一件事设置PC指向文本区域的入口点。
代码托管
本周结对学习情况
- [5324](博客链接)
- 结对照片
- 结对学习内容 第九章
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第十一周 | 300/2000 | 2/2 | 200/400 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
- 计划学习时间:XX小时
- 实际学习时间:XX小时
- 改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)