您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
操作系统之内存管理
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
操作系统之内存管理
自猿其说Tech
2021-04-22
IP归属:未知
586200浏览
计算机编程
大家好,这周来分享一个操作系统的相关知识——内存管理 话不多说,直接开车 ## 物理地址 VS 虚拟地址 - **物理地址**:逻辑上,我们可以把物理内存看成一个大数组,其中每个字节都可以通过与之对应的地址进行访问,这个地址就叫做物理地址 - **虚拟地址** :应用程序在运行时使用的地址 CPU翻译虚拟地址的过程大概如图所示 <center>![](//img1.jcloudcs.com/developer.jdcloud.com/996c9dad-7d2c-448f-9a56-dde033ed1c6220210422143233.png)</center> **他们的包含关系如下**:CPU包含MMU,MMU包含TLB - CPU - MMU(内存管理单元 Memory Management Unit): 负责虚拟地址到物理地址的转换 - TLB(转址旁路缓存 Translation Lookaside Buffer):加速地址翻译的过程 **平常加载程序的顺序是** 1. 操作系统把程序从磁盘加载到内存中(程序一开始是在磁盘中存放的) 2. CPU去执行程序的第一条指令但是这个指令现在在物理内存中 3. CPU取指令取的是该指令的虚拟地址,由MMU翻译为物理地址 4. 这个读物理地址的请求将通过总线,传送到相应的物理内存中,然后物理内存把该指令发送给CPU ## 分段 MMU将虚拟地址翻译为物理地址主要有两种机制 :分段和分页 ### 分段机制 - 操作系统以“段”(一段连续的物理内存)的形式管理/分配物理内存 - 应用程序的虚拟地址空间由若干个大小不同的段组成:代码段、数据段等等 - 当CPU访问虚拟地址中的某一个段的时候,MMU会通过查询段表来得到该段对应的物理地址 <center>![](//img1.jcloudcs.com/developer.jdcloud.com/5196bac2-f404-4fe5-8298-8f7a5281298520210422143534.png)</center> **虚拟地址:** - 段号: 标志着该虚拟地址属于整个虚拟地址空间中的哪一段 - 段内地址(段内偏移): 相对于该段起始地址的偏移量 当 cpu 读取指令时,发现指令的地址是虚拟地址,那么CPU中的MMU 首先判断这个段号是否合法,如果合法, 则通过 段表基址寄存器 找到段表的位置,通过虚拟地址中的段号,找到该段的起始地址,再加上段内地址(段内偏移),就可以得到最终的物理地址 - 在分段机制下,虚拟内存和物理内存都划分成了不同的段 ### **分段缺点** 在虚拟地址空间中,相邻的段所对应的物理内存空间可以不相邻,操作系统能够实现物理内存资源的离散分配,但是这种段式分配方式容易导致在物理内存上出现外部碎片 图中装载不进来的就是外部碎片 <center>![](//img1.jcloudcs.com/developer.jdcloud.com/00a2277d-6237-48ad-b196-cc7445fb2dba20210422143904.png)</center> ## **分页机制** - **基本思想**: - 将应用程序的虚拟地址空间划分为连续的、等长的虚拟页(4K) - 物理地址也是划分为连续的、等长的的物理页 - 物理页和虚拟页页长固定且相等 之所以这样构造是因为会使操作系统很方便的为每个应用程序构造页表,即虚拟页和物理页映射关系表 - 在分页机制下,应用程序虚拟地址空间中的任意虚拟页可以被映射到物理内存中的任意物理页上,可以避免外部碎片的问题 - 分页机制下的虚拟地址也由两部分组成:虚拟页号: 页内偏移量: <center>![](//img1.jcloudcs.com/developer.jdcloud.com/6a4dfd97-1830-44e8-9c90-bb57de66616920210422144043.png)</center> **翻译的具体流程就是**: 1. MMU首先解析虚拟地址中的虚拟页号,检查这个虚拟页号是否合法,通过这个虚拟页号取该应用程序的虚拟页表中找到对应条目(页表起始地址放在页表基地址寄存器) 2. 然后取出该条目中的物理页号 3. 最后用该物理页号对应的物理起始地址加上虚拟地址中的页内偏移得到最终的物理地址 ## **TLB** 首先要说一下局部性原理 - **时间局部性**: 如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行,如果某个数据被访问过,不久后该数据很可能再次被访问(因为程序中存在大量的循环) - **空间局部性**: 一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能会被访问(因为很多数据在内存中都是连续存放的) 所以,能不能弄一个缓存,缓存这些有可能会被经常被访问的数据呢,从而减少访问页表的次数呢? 为了减少地址翻译的访问次数,MMU引入TLB(转址旁路缓存 Translation Lookaside Buffer) - TLB 硬件采用分层架构,分为L1、L2两层。 - LI又分为数据TLB和指令TLB,分别缓存数据和指令的地址翻译 - L2不区分数据和指令 - TLB缓存了虚拟页号和物理页号的映射关系,类似map,key是虚拟页号,value是物理页号。 - 如果在TLB中找到则称为TLB命中 - 没有找到则称之为TLB未命中 <center> ![](//img1.jcloudcs.com/developer.jdcloud.com/e226b2d4-04f4-49c5-aefb-31288ae93a8620210422144308.png)</center> 有了TLB之后,查询就变成了 1.**MMU**首先解析虚拟地址中的虚拟页号,检查这个虚拟页号是否合法,如果合法 - 查TLB,如果命中则 直接取出物理初始地址,再加上页内偏移量得到最终物理地址,否则继续查询页表 - 如果页表中存在物理初始地址,则将此物理初始地址缓存到TLB中通过这个虚拟页号取该应用程序的虚拟页表中找到对应条目(页表起始地址放在页表基地址寄存器) 2.然后取出该条目中的物理页号 3.最后用该物理页号对应的物理起始地址加上虚拟地址中的页内偏移得到最终的物理地址 ## **多级页表** - 如果页表太大时怎么办,页表必须连续存放,会占用很多内存,所以就把一个大表拆成很多小表 拆分后的访问顺序如图所示 <center> ![](//img1.jcloudcs.com/developer.jdcloud.com/1d563827-584b-4095-a76b-ebb56ac3bf1620210422144453.png)</center> - 根据一级页号查找到物理页号,这个物理页号里面装的是二级页表的地址,找到此地址后,再根据二级页号,找到物理地址,此物理地址在加上页内偏移量则为最终的物理地址 ## **换页与缺页异常** ### **换页** 虚拟内存中的**换页**:当物理内存容量不够的时候,操作系统应当把若干物理页的内容写到磁盘这种大容量的地方,然后**回收物理页**并继续使用 举例:有个应用程序A,A的虚拟页K对应物理页V,这个时候,操作系统想回收物理页V,要怎么做呢? - 操作系统把V写到磁盘上 - 并且在A的页表中除去虚拟页K和物理页V的映射,同时记录物理页V被换到磁盘上的对应的位置 以上这两部被称为物理页V的**换出** ### **缺页异常** 缺页异常是换页机制能够工作的前提,当应用程序访问**已经分配但是未映射至物理内存**的虚拟页时,就会触发缺页异常 - 如何解决:通过**换入** - cpu会运行操作系统预先设置的缺页异常处理函数,该函数会找到一个空闲的物理页, - 将以前写入到磁盘上的内容重新加载到该空闲的物理页 - 然后将虚拟地址和此物理地址映射起来 处理完这一切后,cpu回到发生缺页异常的地方继续运行 <center>![](//img1.jcloudcs.com/developer.jdcloud.com/0eb2d95e-40d3-4758-8f4c-423cf6e7180220210422144737.png)</center> ## **段页式内存管理** - **分段管理** - **优点**: 很方便的按照逻辑模块实现信息的共享和保护 - **缺点**: 容易产生外部碎片 - **分页管理** - **优点** 内存空间利用率高,不会产生外部碎片,只会有少量页内碎片 - **缺点**: 不方便按照逻辑模块实现信息的共享和保护 - **段页式内存管理** - 将地址空间按照程序自身的逻辑关系分为若干层,将各段分为大小相等的页面 - 将物理内存与虚拟内存划分为大小相等的一个个的内存块,系统以块为单位为进程分配内存 - 逻辑地址/虚拟地址(段号,页号,页内偏移量) <center>![](//img1.jcloudcs.com/developer.jdcloud.com/4b083d39-8690-4f78-b238-59f9bca5540620210422144927.png)</center> 虚拟地址翻译为物理地址的步骤变为 - 根据逻辑地址取出其中的段号,判断这个段号是否正常 - 如果正常,则找到该段号对应的页表初始地址 - 根据页号是否正常,若正常则根据页号找到物理初始地址,在加上页内偏移量则找到真正的物理地址 <center>![](//img1.jcloudcs.com/developer.jdcloud.com/29c49eef-089b-4177-9611-27ca65902a6520210422145038.png)</center> 若文章有误欢迎指出,靓仔靓女们,我们下篇文章见 ------------ ###### 自猿其说Tech-JDL京东物流技术发展部 ###### 作者:中台技术部-基础平台组 邢焕杰 ------------
原创文章,需联系作者,授权转载
上一篇:目标追踪在物流场景的应用
下一篇:Apple:设计改变世界
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号