操作系统内存管理

概念:

内存管理就是操作系统对内存的划分和动态分配。操作系统内存管理包括物理内存管理和虚拟内存管理。我们程序所使用的内存地址叫做虚拟内存地址,实际存在硬件里面的空间地址叫物理内存地址。操作系统会提供一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起来。

总结:

为了在多进程环境下,使得进程之间的内存地址不受影响,相互隔离,于是操作系统就为每个进程独立分配一套虚拟地址空间,每个程序只关心自己的虚拟地址就可以,实际上大家的虚拟地址都是一样的,但分布到物理地址内存是不一样的。作为程序,也不用关心物理地址的事情。
每个进程都有自己的虚拟空间,而物理内存只有一个,所以当启用了大量的进程,物理内存必然会很紧张,于是操作系统会通过内存交换技术,把不常使用的内存暂时存放到硬盘(换出),在需要的时候再装载回物理内存(换入)。
那既然有了虚拟地址空间,那必然要把虚拟地址「映射」到物理地址,这个事情通常由操作系统来维护。
**那么对于虚拟地址与物理地址的映射关系,可以有分段和分页的方式,**同时两者结合都是可以的。
内存分段是根据程序的逻辑角度,分成了栈段、堆段、数据段、代码段等,这样可以分离出不同属性的段,同时是一块连续的空间。但是每个段的大小都不是统一的,这就会导致外部内存碎片和内存交换效率低的问题。于是,就有了内存分页,把虚拟空间和物理空间分成大小固定的页,如在 Linux 系统中,每一页的大小为4KB。由于分了页后,就不会产生细小的内存碎片,解决了内存分段的外部内存碎片问题。同时在内存交换的时候,写入硬盘也就一个页或几个页,这就大大提高了内存交换的效率,可能会存在较少内碎片。
然后为了解决简单分页产生的页表过大的问题,就有了多级页表来解决空间上的问题,但这就会导致 CPU 在寻址的过程中,需要有很多层表参与,加大了时间上的开销。于是根据程序的局部性原理,在 CPU 芯片中加入了TLB(页表缓存),负责缓存最近常被访问的页表项,大大提高了地址的转换速度。
Linux系统主要采用了分页管理,但是系统无法避免分段管理。于是 Linux 就把所有段的基地址设为0,也就意味着所有程序的地址空间都是线性地址空间(虚拟地址),所以段只被用于访问控制和内存保护。
另外,Linux 系统中虚拟空间分布可分为用户态和内核态两部分,其中用户态的分布:代码段、全局变量、BSS、函数栈、堆内存、映射区。

将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤

1.编译:由编译程序将用户源代码编译成cpu可执行的目标代码(把高级语言翻译成机器语言)。2.链接:由链接程序将编译后形成的一组目标代码及所需的库函数连接在一起,形成一个完整的装入模块3.装入:由装入程序将装入模块装入物理内存运行,装入后形成物理地址

物理内存管理

交换与覆盖:

1.覆盖技术的基本思想:必要的代码和数据常驻内存,不常用的代码在其余模块中实现,并且放在外存,需要时放内存,不存在调用关系的模块不必同时载入内存,可以相互覆盖,共用一个分区。2.交换技术的基本思想:将暂时不运行的程序送到外存以获得空闲内存空间,操作系统在内存管理单元MMU的帮助下把一个进程的整个地址空间的内容保存到外存中,而将外存中的某个进程的地址空间读入到内存中。进程再次换入后的内存地址不一定在原来位置上,可能已被占用,因此需要动态地址映射。
虚拟内存

局部性原理

高速缓存技术利用的是局部性原理,将频繁使用的数据放到更高速的存储器中。局部性原理表现在时间局部性和空间局部性方面:时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)。空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的)

虚拟内存的作用

1.虚拟内存可以使得进程对运行内存超过物理内存大小,因为程序运行符合局部性原理,CPU访问内存会有很明显的重复访问的倾向性,对于那些没有被经常使用到的内存,我们可以把它换出到物理内存之外。2.由于每个进程都有自己的页表,所以每个进程的虚拟内存空间就是相互独立的,进程也没有办法访问其他进程的页表,这就解决了多进程之间地址冲突的问题。3.页表里有一些标记属性,比如控制一个页的读写权限,标记该页是否存在等。在内存访问方面,操作系统提供了更好的安全性。
操作系统有分段和分页两种方式管理虚拟地址和物理地址的关系:
内存分段
程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成,不同的段是有不同的属性的。

虚拟地址和物理地址如何映射:

分段机制下的虚拟地址由两部分组成,段选择因子和段内偏移量。段选择因子就保存在段寄存器里面。段选择因子里面最重要的是段号,用作段表的索引。段内偏移量应该位于0和段界限之间,如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址。分段有两个坏处,一个是外内存碎片但是没有内碎片,外内存碎片需要通过内存交换解决,但是内存交换会引起另一个问题,就是内存交换效率低的问题。比如交换一个比较占内存的程序,那么机器就容易卡顿。为了解决这两个问题,就出现了内存分页。
内存分页
分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫页。在 Linux下,每一页的大小为4KB。虚拟地址和物理地址之间通过页表来映射,页表是存储在内存里的,内存管理单元(MMU)就做将虚拟内存地址转换成物理地址的工作。而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存,更新进程页表,恢复进程的运行。
内存分页由于内存空间都是预先分配好的,页与页之间是紧密排列的,所以不会有外部碎片。但是由于我们分配内存是以一页作为最小单位的,经常程序不足一页大小也需要分配一个页,所以会出现较小的内碎片问题。如果内存空间不够,操作系统会把其他正在运行的进程中,最近没被使用的内存页面给释放掉,也就是暂时写在硬盘上(换出)。一旦需要的时候,再加载进来(换入)。所以,一次性写入磁盘的也只有少数的一个页或者几个页,不会花太多时间,所以内存交换的效率就相对比较高。而且分页让我们不需要一次性把程序都加载到物理内存当中。而是只有在程序运行中,需要用到对应虚拟内存页里面的数据时,再加载到物理内存里面去。
虚拟地址和物理地址如何映射:在分页机制下,虚拟地址分为两部分,页号和页内偏移。页号作为页表的索引,页表包含物理页每页所在物理内存的基地址,这个基地址与页内偏移的组合就形成了物理内存地址。
然而简单分页有一些空间上的缺陷,比如一个页面大小是4kb,一个虚拟空间可以有一百万个页面,每个页表项四个字节,这就一共需要4mb的页表项空间,因为操作系统可以同时运行非常多的进程,这代表页表占用的内存也会比较大,这就需要多级页表解决这个问题。
多级页表
在32位和页大小4KB的环境下,一个进程需要装下100多万个页表项,并且每个页表项是占用4字节大小的,于是相当于每个页表需占用4MB大小的空间。我们把这个100多万个页表项的单级页表再分页,将一级页表分为1024个二级页表,二级页表中包含1024个页表项,形成二级分页。如果是对于64位的系统,两级分页肯定不够了,就变成了四级目录。
多级页表虽然解决了空间上的问题,但是虚拟地址到物理地址的转换就多了几道转换的工序,这就降低了这俩地址转换的速度,我们需要把最常访问的几个页表项存储到访问速度更快的硬件,也就是在cache上加入页表缓存(TLB),有了TLB后,那么CPU在寻址时,会先查TLB,如果没找到,才会继续查常规的页表。

段页式存储管理方式:

然而分段和分页管理并不是对立的,他们可以在一个系统组合起来形成段页式存储管理。段页式是先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制,然后再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页。所以地址结构由段号,段内页号,和页内偏移三部分组成。
段页式地址变换中要得到物理地址有三个过程:1.先访问段表得到页表起始地址;2.再访问页表得到物理页号;3.然后将页号和偏移量组合得到物理地址。
段页式总体看来虽然增加了一点系统开销,但是提高了这个内存利用率。

缺页中断机构

在请求分页系统中,每当所要访问的页面不在内存时,便产生一个缺页中断,请求操作系统将所缺的页调入内存。此时应将缺页的进程阻塞(调页完成唤醒),如果内存中有空闲块,则分配一个块,将要调入的页装入该块,并修改页表中相应页表项,若此时内存中没有空闲块,则要淘汰某页。

地址变换机构

请求分页系统中的地址变换机构,是在分页系统地址变换机构的基础上,为实现虚拟内存,又增加了某些功能而形成的
页面置换算法
进程运行时,若其访问的页面不在内存而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区。
最佳置换算法(OPT)
最佳(OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。但是最佳置换算法可以用来评价其他算法。
先进先出(FIFO)页面置换算法
优先淘汰最早进入内存的页面,亦即在内存中驻留时间最久的页面。该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置一个指针总指向最早的页面。但该算法与进程实际运行时的规律不适应,因为在进程中,有的页面经常被访问。FIFO算法还会产生所分配的物理块数增大而缺页数不减反增的异常现象,这成为Belady异常。
最近最久未使用(LRU)置换算法
选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。该算法为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。LRU性能较好,但需要寄存器和栈的硬件支持,是堆栈类的算法,堆栈类算法不可能出现Belady异常,FIFO是基于队列实现的。
时钟置换算法(CLOCK)(最近未用NRU算法)
简单的算法实现方法
为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)
改进型的时钟算法
简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。算法规则:将所有可能被置换的页面排成一个循环队列
第一轮:从当前位置开始扫描到第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位。
第二轮:若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。本轮将所有扫描过的帧访问位设为0。第三轮:若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位。第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。由于第二轮已将所有帧的访问位设为0,因此经过第三轮、第四轮扫描一定会有一个帧被选中,因此改进型clock置换算法选择一个淘汰页面最多会进行四轮扫描.

页面分配策略:驻留集大小、调入页面的时机以及从何时调入页面

驻留集大小:对于分页式的虚拟内存,在准备执行时,不需要也不可能把一个进程的所有页都读取到主存,因此,操作系统必须决定读取多少页。现代操作系统通常釆用三种策略:
固定分配局部置换。它为每个进程分配一定数目的物理块,在整个运行期间都不改变。若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面。(实现这种策略难以确定为每个进程应分配的物理块数目:太少会频繁出现缺页中断,太多又会使CPU和其他资源利用率下降。)
可变分配全局置换。这是最易于实现的物理块分配和置换策略,为系统中的每个进程分配一定数目的物理块,操作系统自身也保持一个空闲物理块队列。当某进程发生缺页时,系统从空闲物理块队列中取出一个物理块分配给该进程,并将欲调入的页装入其中。
可变分配局部置换。它为每个进程分配一定数目的物理块,当某进程发生缺页时,只允许从该进程在内存的页面中选出一页换出,这样就不会影响其他进程的运行。如果进程在运行中频繁地缺页,系统再为该进程分配若干物理块,直至该进程缺页率趋于适当程度; 反之,若进程在运行中缺页率特别低,则可适当减少分配给该进程的物理块。
调入页面的时机
预调页策略:需要釆用以预测为基础的预调页策略,将预计在不久之后便会被访问的页面预先调入内存。(但目前预调页的成功率仅约50%。故这种策略主要用于进程的首次调入时,由程序员指出应该先调入哪些页。)请求调页策略:进程在运行中需要访问的页面不在内存而提出请求,由系统将所需页面调入内存。策略比较易于实现,故在目前的虚拟存储器中大多釆用此策略。(它的缺点在于每次只调入一页,调入调出页面数多时会花费过多的I/O开销)
从何处调入页面
请求分页系统中的外存分为两部分:用于存放文件的文件区和用于存放对换页面的对换区。对换区通常是釆用连续分配方式,而文件区釆用离散分配方式,故对换区的磁盘I/O速度比文件区的更快。从何处调入页面有三种情况:系统拥有足够的对换区空间:可以全部从对换区调入所需页面,以提髙调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。系统缺少足够的对换区空间:凡不会被修改的文件都直接从文件区调入;而当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时须调到对换区,以后需要时再从对换区调入。UNIX方式:与进程有关的文件都放在文件区,故未运行过的页面,都应从文件区调入。曾经运行过但又被换出的页面,由于是被放在对换区,因此下次调入时应从对换区调入。进程请求的共享页面若被其他进程调入内存,则无需再从对换区调入。

页面抖动和工作集

抖动是指刚刚换出的页面马上又换入主存,刚刚换入的页面马上又换出主存,这种频繁的页面调度行为。工作集指在某段时间间隔内,进程要访问的页面集合。基于局部性原理,可以用最近访问过的页面来确定工作集。为了防止抖动现象,一般来说给进程分配的物理块数(即驻留集大小)要大于工作集大小。

C++内存管理,虚拟内存相关推荐

  1. 13 操作系统第三章 内存管理 虚拟内存 请求分页管理方式 页面置换算法 页面分配策略

    文章目录 1 虚拟内存 1.1 传统存储管理方式的特征.缺点 1.2 局部性原理 1.3 虚拟内存主要特征 1.4 如何实现虚拟内存技术 1.5 虚拟内存的基本概念小结 2 请求分页管理方式 2.1 ...

  2. 虚拟存储器管理c语言_内存管理;虚拟内存

    内存管理 内存管理 操作系统的内存管理主要是做什么? 操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理 ...

  3. 操作系统-内存管理-虚拟内存管理

    目录 一.虚拟内存定义和特征 二.请求分页管理 页表机制 缺页中断机构 地址变换机构 三.页面置换算法 3.1最佳置换算法(OPT) 3.2先进先出置换算法(FIFO) 3.3最近最久未使用置换算法( ...

  4. 操作系统——内存管理——虚拟内存

    考虑一种情况,如果需要运行一个程序,按照之前学习,应该是将该进程全部装入内存中,但是,如果进程所占内存过大,内存不够使用,怎么办?使用虚拟内存. 虚拟内存:每个程序拥有自己的地址空间,这个空间被分割成 ...

  5. Linux内存管理:为什么 Linux 需要虚拟内存?为什么 Linux 默认页大小是 4KB?

    Table of Contents 为什么 Linux 需要虚拟内存? 缓存 内存管理 内存保护 总结 推荐阅读 为什么 Linux 默认页大小是 4KB? 页表项 碎片化 总结 推荐阅读 为什么 L ...

  6. Linux glibc内存管理:用户态内存分配器——ptmalloc实现原理

    文章目录 ptmalloc 设计假设 Arena Chunk Bins 内存分配.释放流程 总结 C++ STL : SGI-STL空间配置器源码剖析 Linux 内存管理 | 物理内存管理:物理内存 ...

  7. Linux 内存管理 | 地址映射:分段、分页、段页

    文章目录 分段 分页 多级页表 快表(TLB) 段页式 Linux Linux 内存管理 | 物理内存管理:内存碎片.伙伴系统.slab分配器 Linux 内存管理 | 虚拟内存管理:虚拟内存空间.虚 ...

  8. C++内存管理全景指南

    导语 深入理解C++内存管理,一文了解所有C++内存问题,万字长文,建议收藏 随着人工智能,云计算等技术的迅猛发展,让Python,go等新兴语言流行了起来,很多人以为C++可能已经过时了,确实,C+ ...

  9. 深入理解C++内存管理

    深入理解C++内存管理 一文了解所有C++内存的问题 AlexCool 目录 一  C++内存模型 二  C++对象内存模型 三 C++程序运行内存空间模型 四  C++栈内存空间模型 五 C++堆内 ...

  10. golang 内存管理

    文章目录 内存管理 内存分配器 线性分配(Bump Allocator) 空闲链表分配(Free-List Allocator) 线程缓存分配 (Thread-Caching Malloc,TCMal ...

最新文章

  1. NeurIPS提前看 | 四篇论文,一窥元学习的最新研究进展
  2. Linux 内核Coding Style整理
  3. tensorflow入门教程和底层机制简单解说——本质就是图计算,自动寻找依赖,想想spark机制就明白了...
  4. Radar Installation(贪心,sort)
  5. Lexus Extroic OpenCart 2.X 自适应主题模板 ABC-0648-03
  6. TCP/IP总结(4)TCP 之数据包格式
  7. 开源牛人 zcbenz
  8. s5pv210——时钟系统
  9. FaunaDB and serverless and bmob
  10. MySQL(12)--- 插入数据
  11. python资格认证_Python怎么实现在后端的自定义认证并且实现多条件登陆
  12. CentOS7校准时间--NTP
  13. python在主线程上下文执行_python进线程
  14. 啊哈C语言——让计算机多彩的开口说话
  15. 宏想固态无法格式化,SM2258XT主控开卡成功经验,SM2259XT可参考
  16. STM32通过IIC驱动MLX90614红外温度传感器
  17. resultFul请求案例
  18. 仿真及设计工具下载安装方法详细说明
  19. pixel-wise,patch-wise,image-wise的含义
  20. ubuntu如何开放对外端口_ubuntu开放指定端口

热门文章

  1. 一曲清商 满墨柔情不知数
  2. MATLAB设计滤波器代码
  3. 精通正则表达式笔记二---正则表达式基础概念?,+,*,{ },\,“ “,时间,小结
  4. 数商云:如何采用电子招投标为企业提升招投标流程的连贯性
  5. AMDCPU双核驱动补丁
  6. springcloud简介与五大组件及相关配置
  7. qt:字符串与hex转换器
  8. Windows 10下无法安装 CAD 2013/2014的解决方法
  9. puppeteer安装“Chromium”已损坏,无法打开。 您应该将它移到废纸篓。
  10. java拼图自动还原算法_自动解决智能拼图,A*算法+生成可解拼图(C++)