[关闭]
@wangjialin 2017-03-29T21:18:50.000000Z 字数 2582 阅读 737

虚拟存储器相关

os


实地址模式 vs 保护模式

  1. 实地址模式是寻址采用和8086相同的16位段寄存器和偏移量,最大寻址空间1MB,寻址是试讲段寄存器的值左移4位加上偏移量,得到1MB以内的实实在在的物理地址
  2. 保护模式下,既可以和之前的机器兼容又可以扩大寻址空间。具体讲就是段寄存器还是16位,但是地址总线增加到32位,也就是说内存扩大到4GB,为了能够扩大寻址空间就不把段寄存器的内容当做实地址模式下的那种用法,而是将他的值当做一个索引,用来在描述符表中找到相应的段描述符,进而找到段基址,从而能够寻址到更大的内存空间
  3. 实地址模式和保护模式的根本在于你直接访问的是实地址还是虚地址,也就是说,进程的内存有没有被保护。实地址模式将内存看做一大块儿区域,系统程序和用户程序没有被区别对待,每一个指针都是指向实实在在的物理地址,也就是说任何程序都可以修改内存里面的任何地方的数据,会造成很严重的后顾;保护模式是程序访问的都是虚地址,内存地址不能直接被程序访问而需要由操作系统转化为物理地址来访问,也就是说程序的访问权限受到了限制,系统会更加安全

虚拟内存机制

假如没有虚拟内存机制,那就是实存管理,具体就是运行一个程序就需要将程序装入内存,需要某个数据的时候就是通过实际地址;多个程序同时在内存里面运行的时候,内存在如何分配和保护;内存里面的程序可能只有一部分正在运行,那么不运行的程序就是在浪费内存空间;编写程序的时候还需要时刻考虑程序所需要占用的内存大小防止没办法在内存较小的计算机上面运行等等,这些都很麻烦,不仅是对于程序员而言,对于用户而言,也不够安全。基于这些不便,提出了虚拟内存的概念,具体就是:不必把整个程序载入内存,只需要将当前使用的部分载入,其他的依旧存放在磁盘中,等待需要使用的时候系统再调到内存中,这个叫做“部分载入”;在没有足够的内存空间的时候可以将一部分暂时不用的信息移到磁盘,这个叫做“部分替换”。有了“部分载入”和“部分替换”,那么相比没有虚拟内存的实存,解决的问题是:
1. 因为可以部分载入,那么多进程环境下,无需太多考虑内存占用的问题
2. 因为可以部分替换,那么多进程环境下,CPU的利用率会更高
3. 不同程序使用库代码时,内存中只需要保留一份即可,使用这份代码的进程只需要将虚拟地址映射到此即可,节省内存
4. 物理内存不连续的碎片地址可以映射到连续的虚拟内存地址,给分配和释放内存带来方便
5.数据每次载入的位置均一致

分页 vs 分段

分页和分段是虚拟存储技术下对存储空间的不同的分块方式。区别在于分块大小是否是由用户决定的
分页
基本原理:分页是将进程的逻辑地址空间分成大小相等的块,用户不必考虑如何分页,而是由硬件地址转换机构和操作系统的管理需要来决定页面尺寸(页框)也就是每一块的内存大小。进程以页框为单位,将自己的地址空间分为若干页,每一页都有一个重定位寄存器,这些重定位寄存器的集合就是每个进程里面唯一的页表。为了减少系统开销,不适用硬件而是在主存中开辟存储区存放进程页表,系统另设专门的硬件——页表机制寄存器来存放当前进程的页表起始地址由基地址和页表就可以转换为真实的物理地址来访问进程代码了
分段
基本原理,和分页类似,只不过分段是由用户根据源程序的逻辑结构来决定如和分段,基于可变分区存储管理,地址转换和分页一致

特权级

在IA32的分段机制下,特权级总共分为4个级别,从高到低分别是
0——操作系统的内核
1,2——服务
3——应用程序
发生系统调用的时候线程会由用户态切为内核态,也就是特权级由3变为0,然后由用户栈切为内核栈,别的没有变化

逻辑地址/线性地址/物理地址

逻辑地址:在需要地址变换的时候,指令直接给出的地址就叫做逻辑地址
线性地址:是逻辑地址到物理地址变换之间的中间层
物理地址:经过寻址方式的计算得到的在存储器中的实际地址就是物理地址

堆和栈的区别

参考:http://www.cnblogs.com/zhangchaoyang/articles/1820787.html
可执行程序(未载入内存)存储时分为代码区,数据区,未初始化数据区三部分。代码区所在的地址空间最低,往上依次是数据区和BSS区,并且数据区和BSS区在内存中是紧挨着的。
1. 代码区存放CPU执行的机器指令。通常代码区是共享的,其它进程可调用它。代码段通常是只读的,有些构架也允许自行修改。
2. 数据区存放已初始化的全局变量,静态变量(包括全局和局部的),常量。static全局变量和static函数只能在当前文件中被调用。
3. 未初始化数据区(Block Started by Symbol,BSS)存放全局未初始化的变量。BSS的数据在程序开始执行之前被初始化为0或NULL。

可执行程序在运行时又多出了两个区域:栈区和堆区。
1. 栈区。由编译器自动释放,存放函数的参数值,局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存储到栈中。然后这个被调用的函数再为它的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用。栈区是从高地址位向低地址位增长的,是一块连续的内在区域,最大容量是由系统预先定义好的,申请的栈空间超过这个界限时会提示溢出,用户能从栈中获取的空间较小。
2. 堆区。用于动态内存分配,位于BSS和栈中间的地址位。由程序员申请分配(malloc)和释放(free)。堆是从低地址位向高地址位增长,采用链式存储结构。频繁地malloc/free造成内存空间的不连续,产生碎片。当申请堆空间时库函数按照一定的算法搜索可用的足够大的空间。因此堆的效率比栈要低的多。

缓冲区溢出

计算机程序一般都会使用到一些内存,这些内存或是程序内部使用,或是存放用户的输入数据,这样的内存一般称作缓冲区。缓冲区溢出,简单的说就是计算机对接收的输入数据没有进行有效的检测(理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据。

危害:缓冲区溢出中, 最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在函数返回时改变返回程序的地址,让其跳转到任意地址,结果一种是程序崩溃导致拒绝服务,另外一种就是跳转并且执行一段恶意代码, 比如得到 shell,然后为所欲为。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注