您当前的位置:首页 > 电脑百科 > 硬件技术 > 内存

计算机内存管理介绍

时间:2020-08-10 13:09:23  来源:  作者:

摘要:

计算机操作系统内存管理是十分重要的,因为其中涉及到很多设计很多算法。《深入理解计算机系统》这本书曾提到过,现在操作系统存储的设计就是“带着镣铐跳舞”,造成计算机一种一种容量多,速度快的假象。包括现在很多系统比如数据库系统的设计和操作系统做法相似。所以在学习操作系统之余我来介绍并总结一些操作系统的内存管理。

首先我们看一下计算机的存储层次结构

计算机内存管理介绍

 

按照金字塔结构可以分为四种类型: 寄存器,快速缓存,主存和外存。而

寄存器和L1缓存都在Processor内部。在金字塔中,越往下价格越低速度越慢但容量越大。

还有两种存储空间需要分清:

  1. 地址空间:又称逻辑地址空间,源程序经过编译后得到的目标程序,存在于它所限定的地址范围内,这个范围称为地址空间。地址空间是逻辑地址的集合。
  2. 内存空间: 又称存储空间或物理地址空间。是指主存中一系列存储信息的物理单元(划重点)的集合,这些单元的编号称为物理地址或绝对地址。

简言之就这两个空间分别是程序员能够观测到的存储空间和真实的物理空间。

需求与管理的目标

需求:

  • 每个程序员希望没有第三方因素干扰程序运行
  • 计算机希望将有限的资源尽可能为多个用户提供服务

为了满足需求的目标:

  • 计算机至少同时存在一个用户程序和一个服务器程序(操作系统内核管理)
  • 每个程序互不干扰,所以其地址空间应该相互独立。
  • 每个程序使用的空间应该被保护,最怕运行的时候程序中断。就和看电影的时候无法播放一样难受。

程序的内存管理

操作系统在内存中的位置有以下三种可能

计算机内存管理介绍

 

只有一个程序的环境下的内存管理

此时整个内存只有两个程序,即用户程序和操作系统。

操作系统所占的空间是固定的,则用户程序空间也是固定的,因此可以将用户程序永远加载到同一个地址,即用户程序永远从同一个地方开始运行。这种情况下,用户程序地址可以在运行之前就可以计算出来。

我们通过加载器计算程序运行之前的物理地址静态翻译。此时既不需要额外实现地址独立和地址保护。因为用户不需要知道物理内存的相关知识,而且也没有其它用户程序。

多个程序的环境下的内存管理

此时用户的程序空间需要通过分区来分给多个不同的程序了。每个应用程序占用一个或几个分区,这种分配支持多个程序并发执行,但难以进行内存分区的共享。

其中分区有两种方法:

一种方法: 固定(静态)式 分区分配, 让程序适应分区

顾名思义就是把内存划分为若干个固定大小的连续分区,这几个分区或者大小相等以适合多个相同程序并发,或者大小不等的分区以适合不同大小的程序。

这种分配方法优点很明显,在于非常容易实现,开销小。

缺点就是会产生很多内部碎片(也就是未被利用的存储空间),固定的分区总数也限制了并发执行的程序数目。我们简单介绍下静态分配的几种方法。

  1. 单一队列的分配方式
  2. 多队列分配方式
  3. 固定分区管理先使用表进行大小初始化,固定分区大小

另一种方法:可变(动态)式 分区分配, 让分区适应程序

此时分区的边界可以移动,但也产生了分区与分区之间狭小的外部碎片。

计算机内存管理介绍

 


计算机内存管理介绍

 

在可变分区中,知道内存的空闲空间大小就十分重要了。OS通过跟踪内存使用计算出内存有多少空闲。跟踪的方法有两种:

位图表示法:

也就是所谓的bitmap,用每一位来存放某种状态。将内存每一个分配单元赋予一个判断的用于判断状态的字位,字位取值位0表示单元闲置;字位为1表示单元被占用

  • 特点
  1. 空间成本固定:不受内存程序数量影响
  2. 时间成本低:操作的时候只需要将状态值改变
  3. 缺少容错能力:由于内存单元发生错误的时会将状态值改变,对操作系统来讲,这个状态值是因为发生错误发生的改变还是原来的状态很难判断。

链表表示法

计算机内存管理介绍

 

​ 将分配单元按照是否闲置链接,P代表这个空间被占用,H代表这个这是一片闲置空间。为了方便遍历查询,每个程序空间的结点接着一个空闲空间的结点每个链表结点还有一个起始地址,与分配单元的大小,用代码表示为

enum Status{P=0,H=1};
struct LinkNode{
    enum Status status;//P表示程序,H表示空闲
    struct LinkNode *begin_address;//起始地址
    size_t size;//闲置空间大小
    struct LinkNode *next;
};
  • 特点空间成本:取决于程序数量时间成本:链表不停的遍历速度很慢,同时还要进行链表的插入和删除修改。有一定的容错能力,可以通过程序空间结点和空闲空间结点相互验证。

可变分区的内存分配

OS通过上面两种跟踪方法知道内存空闲容量,而现在操作系统一般都以链表的形式进行内存空闲容量跟踪。如果有新的程序需要读入内存,可变分区就要对空闲的分区进行内存分配。

内存分配使用两张表:已分配分区表和未分配分区表。用C++描述如下:

//未分配分区表
struct FreeBlock {
    int id;         // 内存分区号
    int address;    // 该分区的首地址
    unsigned length;     // 分区长度
};

//已分配分区表
struct AllocatedBlock {
    int id;         // 内存分区号
    int address;    // 该分区的首地址
    int pid;        // 进程 ID
    unsigned length;     // 分区长度
};

然后OS用双向链表将所有未分配分区表进行串联

struct{
    FreeBlock data;
    Node* prior;
    Node* next;
}Node;

未分配分区表在整个系统空间上的结构如下:

计算机内存管理介绍

 

基于 顺序搜索 的分配算法:

这里我们介绍四种基于顺序搜索的寻找空闲存储空间的算法:

  1. 首次适应算法( First Fit ) :每个空白区按其地址顺序连在一起,从这个空白区域链的始端开始查找,选择第一个足以满足请求的空白块。
  2. 下次适应算法( Next Fit ) :将存储空间中空白区构成一个循环链,每次为存储请求查找合适的分区时,总是从上次查找结束的下一个空闲块开始,只要找到一个足够大的空白区,就将它划分后分配出去。
  3. 最佳适应算法( Best Fit ) : 为一个作业选择分区时,总是寻找其大小最接近(小于等于)于作业所要求的存储区域。
  4. 最坏适应算法( Worst Fit ) :为作业选择存储区域时,总是寻找最大的空白区。

算法举例!!

系统中空闲分区表如下按照地址递增次序排列,现有三个作业分配申请内存空间100K,30K,7K。

区号大小地址状态132K20K未分配28K52K未分配3120K60K未分配4331K180K未分配

  1. 首次适应:从上到下寻找合适的大小申请作业100K,从低地址到高地址找到3号分区,分配完后3号分区起始地址变为100K+60K=160K,剩余空间为120K-100K=20K申请作业30K,从低地址到高地址找到1号分区,分配完后1号分区起始地址变为20K+30K=50K,剩余空间为32K-30K=2K申请作业7K,从低地址到高地址找到2号分区,分配完后2号分区起始地址变为52K+7K=59K,剩余空间为8K-7K=1K结论:优先利用内存低地址部分的空闲分区。但由于低地址部分不断被划分,留下许多难以利用的很小的空闲分区(碎片或零头) ,而每次查找又都是从低地址部分开始,增加了查找可用空闲分区的开销。
  2. 下次适应申请作业100K,找到3号分区,分配完后3号分区起始地址变为100K+60K=160K,剩余空间为120K-100K=20K申请作业30K,从3号分区后继续出发,找到4号分区,分配完后4号分区起始地址变为180K+30K=210K,剩余空间为331K-30K=301K申请作业7K,从4号分区后继续出发,找到1号分区,分配完后1号分区起始地址变为20K+7K=27K,剩余空间为32K-7K=25K结论:使存储空间的利用更加均衡,不致使小的空闲区集中在存储区的一端,但这会导致缺乏大的空闲分区。
  3. 最佳适应算法申请作业100K,找到最适合的3号分区,分配完后3号分区起始地址变为100K+60K=160K,剩余空间为120K-100K=20K申请作业30K,找到最适合的1号分区,分配完后1号分区起始地址变为20K+30K=50K,剩余空间为32K-30K=2K申请作业7K,找到最适合的2号分区,分配完后1号分区起始地址变为52K+7K=59K,剩余空间为8K-7K=1K结论:若存在与作业大小一致的空闲分区,则它必然被选中,若不存在与作业大小一致的空闲分区,则只划分比作业稍大的空闲分区,从而保留了大的空闲分区。最佳适应算法往往使剩下的空闲区非常小,从而在存储器中留下许多难以利用的小空闲区(碎片) 。
  4. 最坏适应算法申请作业100K,找到4号分区,分配完后3号分区起始地址变为180K+60K=240K,剩余空间为331K-100K=231K申请作业30K,此时被分配过的4号分区依然容量最大,于是还是找到4号分区,分配完后4号分区起始地址变为240+30K=250K,剩余空间为231K-30K=201K申请作业7K,此时被分配过的4号分区依然容量最大,找到4号分区,分配完后4号分区起始地址变为250+7K=257K,剩余空间为201K-7K=194K结论:总是挑选满足作业要求的最大的分区分配给作业。这样使分给作业后剩下的空闲分区也较 大,可装下其它作业。由于最大的空闲分区总是因首先分配而划分,当有大作业到来时,其存储空间的申请往往会得不到满足。

基于顺序搜索的分配算法实际上只适合小型的操作系统,大中型系统使用了是比较复杂的索引搜索的动态分配算法。

如何回收内存

  1. 回收分区上邻接一个空闲分区,合并后首地址为空闲分区的首地址,大小为二者之和。
  2. 回收分区下邻接一个空闲分区,合并后首地址为回收分区的首地址,大小为二者之和。
  3. 回收分区上下邻接空闲分区,合并后首地址为上空闲分区的首地址,大小为三者之和。
  4. 回收分区不邻接空闲分区,这时在空闲分区表中新建一表项,并填写分区大小等信息。

用iPad画了一个简单的示意图如下:

计算机内存管理介绍

 

最后

内存分配实际上是操作系统非常重要的一环,如果仅限于理论而不写代码实践则容易迷惘,很多具体的实现与都比较困难。如上面的基于顺序搜索的最佳适应算法,比如几个分区的表示方法,都用到了数据结构和算法的知识。如果能用C或者C++完成上述几个算法和操作的具体实现,相信一定会大有脾益的。



Tags:内存管理   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
本文首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友分析Lin...【详细内容】
2021-08-26  Tags: 内存管理  点击:(79)  评论:(0)  加入收藏
对于精通 CURD 的业务同学,内存管理好像离我们很远,但这个知识点虽然冷门(估计很多人学完根本就没机会用上)但绝对是基础中的基础。这就像武侠小说中的内功修炼,学完之后看不到立...【详细内容】
2020-12-09  Tags: 内存管理  点击:(191)  评论:(0)  加入收藏
作者:前端小混混 来源:前端先锋作用域JavaScript 的变量被作用域所限制,如果超出了作用域,那么变量就没有办法再被使用,这样做的优点是: 可以避免当前的变量转为全局变量 有效限制...【详细内容】
2020-11-09  Tags: 内存管理  点击:(112)  评论:(0)  加入收藏
Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee Fℹ️ 这篇文章基于 Go 1.13。在内存从分配到回收的生命周期中,内存...【详细内容】
2020-09-24  Tags: 内存管理  点击:(65)  评论:(0)  加入收藏
前面讲到过写时复制缺页异常(COW),一般用于父子进程之间共享页,而我们会常见一种缺页异常是匿名映射缺页异常,今天我们就来讨论下这种缺页异常,让大家彻底理解它。注:本文使用linux-5.0内核源代码。文章分为以下几节内容:...【详细内容】
2020-09-10  Tags: 内存管理  点击:(90)  评论:(0)  加入收藏
摘要:计算机操作系统内存管理是十分重要的,因为其中涉及到很多设计很多算法。《深入理解计算机系统》这本书曾提到过,现在操作系统存储的设计就是“带着镣铐跳舞”,造成计算机...【详细内容】
2020-08-10  Tags: 内存管理  点击:(126)  评论:(0)  加入收藏
Python作为一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存管理,Python解释器给你自动回收。开发人员不用过多的关...【详细内容】
2020-07-29  Tags: 内存管理  点击:(72)  评论:(0)  加入收藏
之前写过一篇《CPU是如何访问内存的?》的文章,简单介绍了cpu访问内存的过程。有了之前的感性认识,这篇站在arm的角度再深度讲解一下,看完你会发现不理解arm原理就直接撸内核代码...【详细内容】
2020-06-18  Tags: 内存管理  点击:(76)  评论:(0)  加入收藏
这一节我们先简单聊一下redis配置与版本注意事项,涉及到配置,键的过期、32位redis和64位的区别,后续我们再来了解Redis LRU键的驱逐策略以及具体的优化策略。1、配置redis如果...【详细内容】
2020-06-10  Tags: 内存管理  点击:(79)  评论:(0)  加入收藏
Java与C++之间有一堆由内存动态分配与垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来。 —— 《深入理解Java虚拟机:JVM高级特性与最佳实践》...【详细内容】
2020-05-12  Tags: 内存管理  点击:(47)  评论:(0)  加入收藏
▌简易百科推荐
从增强现实到人工智能、云计算再到物联网,5G正在燃爆新技术增长,同时也在燃爆它们生成的数据量。数据量越来越大,随之而来的是存储和快速访问需求,DDR5之类的技术变得空前重要。...【详细内容】
2021-05-21  电子工程世界  今日头条  Tags:DDR5   点击:(126)  评论:(0)  加入收藏
电脑配内存条时会发现一个现象:同样是16G容量的内存,单条16G比两条8G价格要略微便宜,两条8G组成双通道又似乎是绝大多数人推荐的配置。它们之间到底有什么不同呢?主要有以下三点...【详细内容】
2021-04-08    数智风  Tags:内存   点击:(240)  评论:(0)  加入收藏
对于内存来说,普通消费者更在乎的是品牌与容量,在选购电脑挑选多大的容量内存,才能满足自身需求,不错的品牌主要体现内存品质以及售后的保障。不过对于DIY发烧人群来说,超频至极...【详细内容】
2020-12-23      Tags:内存   点击:(159)  评论:(0)  加入收藏
如果你想组装一台高配电脑,一定会希望 灯光很闪 所有规格都拉满,而在内存条这一项上「频率」通常是大家最看重的参数。理论上,内存的工作频率等同于内存的处理速度,频率越高,处理...【详细内容】
2020-10-27      Tags:内存   点击:(161)  评论:(0)  加入收藏
一、读懂内存命名很多电脑小白在看到内存名字的时候都一脸懵逼,一长串的名字只能看懂品牌名。后面的“DDR4、3200”等参数,根本看不懂。我们以芝奇皇家戟这根内存为例,其名为“...【详细内容】
2020-09-07      Tags:内存条   点击:(1437)  评论:(0)  加入收藏
突然发现好长时间没有跟大家讲电脑相关的知识了,而且,私信也有很多人在问这方面的问题。所以,我总结了一下问的最多的问题,今天来跟大家探讨一下。其中问题最多的一个就是电脑...【详细内容】
2020-08-27      Tags:内存   点击:(784)  评论:(0)  加入收藏
[PConline 评测]一直以来,用户对内存的需求似乎仅停留在容量上,17年的吃鸡风潮一起,引领了一波内存升级的热潮,但自从主机的内存标配从4Gx2变成了8Gx2,大家对内存的关注度也逐渐...【详细内容】
2020-08-24      Tags:内存   点击:(111)  评论:(0)  加入收藏
大家好,我是黄昏百分百,大家都知道内存的频率越高,电脑的性能越高,但是却并不清楚高频率内存对电脑的性能到底有多少。今天我就为大家带来详细的测试,看一看电脑内存频率的高低,对...【详细内容】
2020-08-14      Tags:高频内存   点击:(120)  评论:(0)  加入收藏
大家好,我是小匠。我们经常停建或者听到128G“内存”的手机才卖1999,那凭什么一对高端的8G 内存套条敢卖1000?内存有成为随机存储器(RAM),而手机单习惯将内置存储(ROM/外部存储器)称...【详细内容】
2020-08-10      Tags:内存   点击:(180)  评论:(0)  加入收藏
摘要:计算机操作系统内存管理是十分重要的,因为其中涉及到很多设计很多算法。《深入理解计算机系统》这本书曾提到过,现在操作系统存储的设计就是“带着镣铐跳舞”,造成计算机...【详细内容】
2020-08-10      Tags:内存管理   点击:(126)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条