操作系统 —— 内存管理

内存管理解决的问题

内存虚拟化是为了解决两个突出问题:

  1. 多个进程装入内存内存不够用。 (解决:分页,然后使用交换算法LRU,使用的放进去,不使用的换出来)
  2. 内存之间程序互相打扰访问。不小心访问到别人的内存空间。(解决:虚拟内存)

虚拟内存

虚拟内存(逻辑内存)和物理内存

虚拟内存:将一个小内存虚拟成为一个大的连续的独占的内存空间。从进程角度看:自己占用一块独一无二空间。
物理内存:计算机实际的内存空间

虚拟内存怎么实现的

  1. 地址转换:当访问虚拟内存时,MMU(内存管理单元)去匹配对应的物理地址。也就是将逻辑地址转换为物理地址。找到实际的物理内存地址,CPU读取内存。
  2. 使用交换空间:把一部分运行的程序内存放到物理内存,另一部分不常用的放到硬盘中。物理内存只存储一些必要的进程内存。还有一部分存储在外部磁盘存储器上,在需要时进行数据交换。当虚拟内存的页并不存在于物理内存中,会产生缺页中断,从硬盘中取得缺的页放入内存,如果物理内存已满,还会根据某种算法LRU将磁盘中的页换出。

为何使用虚拟内存(好处)

  1. 隔离:为了保证互不影响,我们让进程工作在自己私有的虚拟空间。原来的操作系统,AB进程装进来,A的进程可以访问B的进程内存地址。使用虚拟内存来解决。然后由操作系统将这些虚拟空间地址映射到物理地址空间。这样每个程序都运行在自己私有的虚拟空间不会影响其他程序。实现了内存隔离互不打扰。
  2. 提高内存使用空间: 虚拟内存实际上可以比物理内存大。每个进程都认为自己拥有4G的空间,(这只是每个进程认为的)但是实际上,他只在物理内存上占用很小的空间。
  3. 提升系统并发度。由于每个进程只有一小部分存在于物理内存,这样物理内存中可以保留更多进程,系统并发度提高。

虚拟(逻辑)地址和物理地址

  • 逻辑地址:给用户提供虚拟的逻辑地址的概念,用户认为自己使用的地址空间是从0开始且连续的更加方便用户使用,但是这个地址映射到物理地址上可能是非连续的。然后由操作系统将逻辑地址映射到物理地址
  • 物理地址:实际内存中的地址。

作用:1. 保护物理内存,隔离不同进程。2. 方便进程使用。

逻辑地址和物理如何转换

操作系统完成:
动态重定位

  1. 通过基址加虚拟地址,也就是逻辑地址加地址空间偏移量的方式,使用MMU映射到物理地址。
  2. 通过界限寄存器就防止越界访问,如果用户程序越界访问,则CPU产生异常,操作系统就会去处理。这样就起到防止进程访问到其他地址空间访问到其他进程。

内存页交换策略

https://blog.csdn.net/baidu_28312631/article/details/47414645
产生场景:程序要使用的页不存在于物理内存中,会产生缺页中断,从硬盘中取得缺的页放入内存,如果物理内存已满,还会根据某种算将磁盘中页进行交换。

  1. FIFO:先进先出,谁先进来谁就先出去。但是可能剔除重要的页。
  2. LRU:最近使用原则:每个最近被访问的都会被提到队头,然后删除最久未访问的。
  3. LFU:最不常用算法:每个访问页计数,置换访问次数最少的页面,将计数最小的替换。
  4. 时钟置换算法(Clock):是FIFO和LRU的折中。环形链表,不再排序而是使用2个标记,0和1,第一个次加载到该页的时候,页标记被设置为0,内存中再次访问该页则标记该页面为1。当需要替换时,指针从当前位置循环查找环形链表(类似于FIFO),如果遇到标记为1的,标记为0,不替换,如果遇到标记为0的,替换它

Linux交换空间和虚拟内存的区别

  1. 虚拟内存是进程概念,交换空间是操作系统概念
  2. 虚拟内存主要解决进程物理内存不足,而交换空间主要解决系统物理内存不足(比如系统休眠,就把系统放入硬盘中)。

内存分配API

在运行一个C程序等时候,内存会分配两种类型内存:一种叫栈内存,一种叫堆内存。
当程序运行的时候,会根据我们写的代码比如c++中new去在内存中开辟堆空间,或者栈空间等。这个空间就是该程序运行时所需要的内存空间。
内存分配可能会产生很多问题,所以程序员在使用的时候要注意:比如,忘记释放内存造成内存泄漏,反复释放内存等。

为何我们没有释放内存,一般进程退出时不会内存泄漏

因为操作系统有两层内存管理,第一层就是我们手动分配和释放内存。第二层是操作系统做的,他会在你的进程退出时,将所有该进程相关的没有被释放的内存释放掉(即使你忘记释放)。所以一般我们运行较短的时间程序,有一些内存泄漏也并不会影响程序和操作系统。但是如果时长时间服务器运行的程序,没有退出,那么长时间累积就会造成大量内存泄漏积累而导致计算机因内存不足而崩溃。

页式存储管理和段式存储管理

https://www.cnblogs.com/wkfvawl/p/11700301.html

段式存储管理

如果我们将整个程序地址空间都直接放入物理内存,程序分为代码,栈,堆。那么栈和堆之间空间没有被使用却占用了内存,这样造成了内存极大的浪费。
所以使用分段机制,将进程地址空间里是分三个段:代码,栈,堆。把这三个段分别独立放到物理内存中的不同位置,中间空隙。这样更高效的利用物理内存。

问题:产生页外碎片。分段会将物理内存空间分成不同长度的段,空间本身会碎片化,这对于操作系统再次给其他进程分配内存造成了麻烦。不同的段和段之间内存中的空隙比较小的话,就不能插入一个段,这样会有很多的段之前都产生碎片,这就是页外碎片。

页式存储管理

而如果我们把空间分成固定长度的单元,这样计算机在处理起来就会更加方便快速,解决外碎片问题,这个固定长度单元我们称之为分页。 把程序分成一页一页的,然后装入内存中的页。比如物理内存中分页4k,然后把程序页内存大小也分为4K
分页的页表存储着虚拟页的页号,和对应的物理内存的页号,然后通过加偏移量加虚拟地址来进行地址转换。

如何使用呢?

就是用到哪一块程序的页,我们就把该页放入内存中。
所以现在内存管理,是把程序大卸八块,用到哪块装哪块进内存。
硬盘内存:在过程中如果当前内存满了,那么我们把最不常用的内存块放到交换分区swap(硬盘),如果要使用该块,则再拿回来,把这个再装入内存。这个就是页面置换算法(涉及到缓存的基本都是这个算法)。

问题:1. 一段连续逻辑分布在多个页中,则大大降低执行效率. 2. 容易产生页内碎片,有的页比较大,程序内存不满一个页,那么这个页内就会空出很多空间。

页表访问

访问分页系统中内存数据需要两次的内存访问(一次是从内存中访问页表,从中找到指定的物理块号,加上页内偏移得到实际物理地址;第二次就是根据第一次得到的物理地址访问内存取出数据)。

快表

为了减少两次访问内存导致的效率影响,分页管理中引入了快表机制,相当于再加一层缓存,是一种访问速度比内存快很多的高速缓存,用来存放最近访问的页表项的副本,可以加速地址变换的速度(基本地址变换机构要访存2次)当要访问内存数据的时候首先将页号在快表中查询,如果查找到说明要访问的页表项在快表中,那么直接从快表中读取相应的物理块号;如果没有找到,那么访问内存中的页表,从页表中得到物理地址,同时将页表中的该映射表项添加到快表中。

在某些计算机中如果内存的逻辑地址很大,将会导致程序的页表项会很多,而页表在内存中是连续存放的,所以相应的就需要较大的连续内存空间。为了解决这个问题,可以采用两级页表或者多级页表的方法,其中外层页表一次性调入内存且连续存放,内层页表离散存放。相应的访问内存页表的时候需要一次地址变换,访问逻辑地址对应的物理地址的时候也需要一次地址变换,而且一共需要访问内存3次才可以读取一次数据。

段页式存储管理:

先把程序的内存按段分成若干段,满足程序需求,因为程序按段来划分执行效率更高。
再把段按照页式管理分成若干页,并将页存放到物理内存中。提高计算机内存效率。
这样既满足了用户需求,又满足计算机需求,减少内存碎片。
页是物理单位,从物理角度
段时逻辑单位,主要时满足用户需求,段的划分是不固定的。

猜你喜欢

转载自blog.csdn.net/chongbin007/article/details/114859067
今日推荐