一、几个基本的概念
1.存储器的金字塔结构
存储器从下之上依次是磁盘/flash、DRAM(内存)、L2-cache、L1-cache、寄存器,越在上面的存储器访问速度越快,同时价格也越昂贵,每一级都可以看做是下一级的缓存,内存是磁盘的缓存,cache是内存的缓存。
2.地址空间
地址空间就是一个非负正数的有序集合,如果是连续的即线性地址空间,从硬件的角度看就是处理器所能访问的存储器空间,与地址线的位数相关,物理地址空间就是物理存储器的访问空间(按字节访问)
3.页
将物理内存和虚拟内存按页来划分,页的大小也有所不同,ARM中支持1M的大页,4k或64k的细页,x86下支持4M的大页,利用页表来表征整个地址空间,当采用二级页表时,存在一个页目录,用来索引对应页表所在的物理地址,PTE页表项占4个字节,当采用4k大小的页时,一个虚拟地址可以划分为:
31 22 21 12 11 0
| 页目录索引 | 页表索引 | 页内偏移 |
硬件页表项PTE
31 22 0
| 物理页帧号 | 物理页属性和访问控制 |
二、地址转译
地址的转译是有虚拟地址至物理地址,处理器内使用的是虚拟地址,经过MMU转译为物理地址,例如DMA使用的就是物理地址,因为它在MMU之后,转译的过程是MMU与OS配合完成的,OS负责维护页表,MMU负责翻译,要明确一点是MMU使用的是物理地址。首先根据页目录的物理地址(x86在CR3中)和页目录索引查找到页目录表项PDE,其中记录了对应页表的物理地址,如果该页表在物理内存中(页表也可以被换出到磁盘中),PDE表项的格式与硬件PTE基本一致,然后根据页表索引找到对应的页表项PTE,最后根据其中的物理页帧号和页内偏移计算得到物理地址。
具体的翻译过程用一个例子来说明:
例如:一个虚拟地址为0x50001,页目录索引为0x0,页表索引为0x50,页内偏移为0x1,首先找到PDE(windows的虚拟地址空间PDE_0的VA = 0xc0300000),PDE物理地址 = CR3 + 0x0(页目录索引)*4,PDE表项内容为0x00700 067,查找PTE,PTE物理地址 = 0x700 + 0x50(页表索引)*4,(PTE的虚拟地址为0xc0000140),PTE表项的内容为0x00e63 047,则最终转译的物理地址 = 0xe63 000 + 0x1 = 0xe63001
三、虚拟内存的原理
如何在物理内存有限的情况下例如只有32MByte,可以使系统寻址4G的地址空间,物理内存资源是一种共享的稀缺资源,因此虚拟地址空间的页并不是都有对应的物理内存页面,将某一时刻处理器不访问的虚拟页面以页的方式保存在磁盘上,当需要读写时再将其换入至物理内存中。
四、进程虚拟地址空间
x86体系结构下,一个进程的虚拟地址空间为4G,主要包括了进程的私有地址空间和系统地址空间两部分,windows中0x0--0x7fff ffff作为进程私有,0x8000 0000 -- 0xffff ffff为系统地址空间。
1.大页和小页
采用大页的好处是在TLB中可以缓存更大的地址空间,增加了缓存命中的概率,不好的一点是页面粗粒度造成的不安全访问,例如.data(读写)和.text(只读)都放在同一个具有读写权限的页面内,则有可能造成.text的内容误写,可能导致系统崩溃。
采用小页的好处是细粒度管理内存,更加灵活,更少的内部碎片,但同时PFN更多,管理的开销要更大一些。
因此为了安全可靠,选用小页,4K page
2.延迟计算
(1)先保留再提交内存
当一个线程申请大块的虚拟内存时,现在虚拟地址空间中保留一段范围,为一块虚拟内存建立虚拟地址描述符(VAD),当真正访问这段地址空间时,再建立PTE,也就是在物理内存中分配有效的页面。一个应用例子就是每个线程的用户栈在创建时首先会保留1MB的空间,只有在虚拟页面被访问时才会提交。在VAD中记录了地址范围的大小,以及读写权限,当建立PTE时就根据VAD中记录的信息(读写权限)来填充PTE。
(2)写时复制 copy-on-wirte
i.当两个进程共享一个写时复制的物理页面时,如果其中一个进程中的线程要对共享页面进行写操作,则产生一个内存管理错误(一个异常),内存管理器为其分配一个新的读写物理页面,并且将原始共享页面的内容复制到新的物理页面中,并将虚拟地址映射更新为新的物理页面,控制权返回线程,线程执行写操作,此时新的物理页面属于该进程私有,其他进程是看不到的,也就是说写时复制为执行写操作的进程创建了一份私有的拷贝。
ii.POSIX子系统利用写时拷贝来创建子进程的地址空间,首先父进程创建一个子进程,子进程的地址空间是共享父进程的地址空间,将地址空间标记为写时拷贝,只有子进程执行写操作时,才会拷贝相应的页面给子进程私有使用。
3.内存区对象
section object,每一个打开的文件都有一个内存区对象指针,根据文件类型的不同(数据文件或可执行文件)指向不同的控制区域(虚拟地址空间内),控制区域包括子内存区,例如一个可执行文件的子内存区就是.data,.text,.bss等,同时这个控制区域又指向了一些原型PTE,通过这些原型PTE可映射到该内存区对象所映射的实际物理页面。
当内存区对象指向一个很大的数据文件时,线程只访问其中的一部分,就只映射该内存区中的一部分,这部分被称为内存区视图。
内存区对象的应用,映像加载器利用它加载可执行文件,缓存管理器利用它来访问缓存文件中的数据,这两者都是针对打开的文件,共享内存的应用是内存区对象与物理内存关联。
虚拟页有三种状态,已提交的,保留的和未分配的。
4.windows的四种内存保护机制
(1)系统空间的全局数据结构和内存池只有在内核模式下才可以访问,用户线程无法访问这些页面
(2)每个用户进程都有自己的私有地址空间,这部分空间是其他进程无法访问的
(3)地址转译过程中的隐式保护,一个标记为只读的页在对其进行写操作时会产生页面访问错误
(4)共享内存区对象具有标准的windows访问控制列表,对于没有权限的进程,是无法访问共享内存区的
5.进程页表
一个进程有自己的页目录,这个页目录就指向了对应的页表,进程的系统空间都是共享的,因此页表也是共享系统空间页表项,一个进程在创建时会初始化地址空间,也就是初始化页表,第一阶段就是创建系统空间的页表项,就是将页目录的PDE指向系统空间的页表,然后是打开一个可执行文件建立一个内存区对象,再映射至进程的私有空间,实质上是先保留地址空间,当进程执行时根据读写页面的需要创建PTE,进程的会话空间页表也是共享的,即指向已有的会话页表。进程的页目录和页表所在的物理页被映射至0xc0300 000和0xc000 0000
6.TLB
TLB就是缓存了虚拟页至物理页的映射,本质上就是一个cache,进程切换时会刷新TLB,但是系统空间的TLB项不会刷新,因为进程的系统空间是共享的
7.页面错误处理
页面处理的错误有两种,(1)访问了没有物理页映射的虚拟地址 (2)以错误的方式访问
8.原型PTE
首先原型PTE是一种无效PTE,目的是让所有可能需要共享页面的进程的PTE都指向原型PTE来解决页面错误,原型PTE是伴随这共享页面的内存区一起创建的,当共享内存页面是有效时,进程都直接用自己的PTE来访问。
当共享内存页面无效时,如果没有原型PTE,那如果一个进程访问该共享页面将其换入内存中,那内存管理器要将所有共享该内存页的进程的页表进行更新,告诉他们共享内存页有效了,这样做比较费力。
现在使用原型PTE,当进程访问的共享页无效时,则将该PTE指向共享页的原型PTE,如果进程A再次访问该页,共享页又被换入内存中,此时要更新原型PTE指向新的物理页,当进程B再次访问共享页时,此时因为原型PTE已经得到更新,则内存管理器更新进程B的页表,使其PTE指向新的物理页。
原型PTE的精髓还是延迟计算,就是当一个共享页从新被换入内存时,不必去更新所有曾经访问过该共享页的进程页表,而是等到进程真正访问时再去更新。
9.换页策略
(1)最近最少使用
(2)先进先出 将驻留在内存中最久的页面换出
(3)时钟算法
- Windows内核 内存管理基本概念
内存管理概念: 1)物理内存 PC上有三条总线:数据总线.地址总线和控制总线.32位CPU的寻址能力是4GB个字节,用户最多可以使用4GB的真实物理内存.PC中很多设备都提供了自己的设备内存,例如显卡 ...
- linux内核--内核内存管理
如题目所示,为什么要称作“内核内存管理”,因为内核所需要的内存和用户态所需要的内存,这两者在管理上是不一样的. 这篇文章描述内核的内存管理,用户态的内存管理在以后的文章中讲述. 首先简单的说明一下下面 ...
- Linux内核内存管理架构
内存管理子系统可能是linux内核中最为复杂的一个子系统,其支持的功能需求众多,如页面映射.页面分配.页面回收.页面交换.冷热页面.紧急页面.页面碎片管理.页面缓存.页面统计等,而且对性能也有很高的要 ...
- Linux内核内存管理算法Buddy和Slab: /proc/meminfo、/proc/buddyinfo、/proc/slabinfo
slabtop cat /proc/slabinfo # name <active_objs> <num_objs> <objsize> <objpersla ...
- Linux0.11内核--内存管理之2.配合fork
[版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5598451.html ] 在上一篇的fork函数中,首先一上来就调用get_free_page ...
- Linux0.11内核--内存管理之1.初始化
[版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5597705.html ] Linux内核因为使用了内存分页机制,所以相对来说好理解些.因为内存 ...
- Linux内核内存管理子系统分析【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51298718 版权声明:本文为博主原创文章,未经博主允许不得转载. 还是那张熟悉 ...
- (笔记)Linux内核学习(九)之内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- Linux内核学习笔记——内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
随机推荐
- Spring - 配置Bean - 自动装配 关系 作用域 引用外部属性文件
1 Autowire自动装配1.1 使用:只需在<bean>中使用autowire元素<bean id="student" class="com.kej ...
- 块级元素和内联元素的区别(HTML)
请把下面二行代码放进body标签里: <div style=”border: 1px solid red;”>div1</div> <div style= ...
- 运用datalist标签实现用户的搜索列表
datalist是一个很强大的HTML5标签,支持一般类似于模糊查询,以前都是需要js来做的.下面是一个datalist配合js的小例子,主要是实现用户是否存在,以及添加过程中是否重复的判断. 首先是 ...
- Android内存进程管理机制
参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...
- Thread 的使用
对于Thread 的使用,我要注意的是我经常忽略".start()".之前由于在android开发中,如果是使用网络加载的功能,这个部分需要新增线程,不能在主线程使用. 然后注意要 ...
- 关于dialog置于底层的问题
我今天开发的一个dialog,引用代码中已有的,发现是居中的 接下来,我要把它置为底部 然后,我的思路就是从dialog的view设置入手,还用了setgravity,最后还是不成功 所以,后来,我休 ...
- 2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)
I. Sale in GameStore(贪心) time limit per test 2 seconds memory limit per test 512 megabytes input sta ...
- Codeforces Round #253 (Div. 2) B - Kolya and Tandem Repeat
本题要考虑字符串本身就存在tandem, 如测试用例 aaaaaaaaabbb 3 输出结果应该是8而不是6,因为字符串本身的tanderm时最长的 故要考虑字符串本身的最大的tanderm和添加k个 ...
- 【BZOJ】1086: [SCOI2005]王室联邦
http://www.lydsy.com/JudgeOnline/problem.php?id=1086 题意:n个点的树,要求分块,使得每一块的大小在[b, 3b]内且块与某个点形成的块是连通的(某 ...
- POJ 1654 Area(水题)
题目链接 卡了一下精度和内存. #include <cstdio> #include <cstring> #include <string> #include &l ...