操作系统内存管理、Cache调度策略学习

目录

0. 引言
1. 内存管理的概念
2. 内存覆盖与内存交换
3. 内存连续分配管理方式
4. 内存非连续分配管理方式
5. 虚拟内存的概念、特征及其实现
6. 请求分页管理方式实现虚拟内存
7. 页面置换算法
8. 页面分配策略
9. 页面抖动和工作集

0. 引言

在安全攻防产品的研发中,我们会大量用到cache的机制。在学习和使用cache缓存的时候,经常会遇到cache的更新和替换的问题,如何有效对cache进行清理、替换,同时要保证cache在清理后还要保持较高的命中率。通过对比我们发现,操作系统的内存管理调度策略和cache的动态更新策略本质是类似的,通过学习操作系统的内存管理策略,我们可以得到很多关于cache更新的策略思想

Relevant Link:

https://www.google.com.hk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=27&ved=0CDwQFjAGOBQ&url=%68%74%74%70%3a%2f%2f%6f%61%2e%70%61%70%65%72%2e%65%64%75%2e%63%6e%2f%66%69%6c%65%2e%6a%73%70%3f%75%72%6c%74%69%74%6c%65%3d%25%45%36%25%39%36%25%38%37%25%45%34%25%42%42%25%42%36%43%61%63%68%65%25%45%38%25%38%37%25%41%41%25%45%39%25%38%30%25%38%32%25%45%35%25%42%41%25%39%34%25%45%37%25%41%44%25%39%36%25%45%37%25%39%35%25%41%35%25%45%37%25%41%30%25%39%34%25%45%37%25%41%39%25%42%36&ei=veo1VN_RJZfj8AWBnoCACQ&usg=AFQjCNHVjRFlRvV-0O1tYyb4Inv33Pop4A&bvm=bv.76943099,d.dGc&cad=rjt

1. 内存管理的概念

内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件一直在飞速发展,内存容量也在不断增长,但是仍然不可能将所有用户进程和系统所需要的全部程序和数据放入主存中,所以操作系统必须将内存空间进行合理地划分和有效地动态分配。
操作系统对内存的划分和动态分配,就是内存管理的概念。有效的内存管理在多道程序设计中非常重要,不仅方便用户使用存储器、提高内存利用率,还可以通过虚拟技术从逻辑上扩充存储器。

内存管理的功能有:

1. 内存空间的分配与回收:
由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率

2. 地址转换:
在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,因此存储管理必须提供地址变换功能,把逻辑地址转换成相应的物理地址

3. 内存空间的扩充:
利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存

4. 存储保护:
保证各道作业在各自的存储空间内运行,互不干扰

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2608.html


2. 内存覆盖与内存交换

0x1: 内存覆盖

早期的计算机系统中,主存容量很小,虽然主存中仅存放一道用户程序,但是存储空间放不下用户进程的现象也经常发生,这一矛盾可以用覆盖技术来解决。

覆盖的基本思想是:由于程序运行时并非任何时候都要访问程序及数据的各个部分(尤其是大程序),因此可以把用户空间分成一个固定区和若干个覆盖区。将经常活跃的部分放在固定区,其余部分按调用关系分段。首先将那些即将要访问的段放入覆盖区,其他段放在外存中,在需要调用前,系统再将其调入覆盖区,替换覆盖区中原有的段。

覆盖技术的特点是打破了必须将一个进程的全部信息装入主存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行

将内存覆盖技术和cache更新技术进行类比,等效于对cache直接进行"简答替换(简单删除)",即不采用任何的排序和选择策略,粗暴地将cache中的某一段数据清空出去,这种方法不适合在高并发、大流量的场景下

0x2: 内存交换

交换(对换)的基本思想是:
1. 把处于等待状态(或在CPU调度原则下被剥夺运行权利)的程序从内存移到辅存,把内存空间腾出来,这一过程又叫换出
2. 把准备好竞争CPU运行的程序从辅存移到内存,这一过程又称为换入 

有关交换需要注意以下几个问题:

1. 交换需要备份存储,通常是快速磁盘。它必须足够大,并且提供对这些内存映像的直接访问。
2. 为了有效使用CPU,需要每个进程的执行时间比交换时间长,而影响交换时间的主要是转移时间。转移时间与所交换的内存空间成正比。
3. 如果换出进程,必须确保该进程是完全处于空闲状态。
4. 交换空间通常作为磁盘的一整块,且独立于文件系统,因此使用就可能很快。
5. 交换通常在有许多进程运行且内存空间吃紧时开始启动,而系统负荷降低就暂停。
6. 普通的交换使用不多,但交换策略的某些变种在许多系统中(如UNIX系统)仍发挥作用。

需要注意的是,覆盖技术则已成为历史;而交换技术在现代操作系统中仍具有较强的生命力。我们今天在操作系统原理相关书籍上学习的相关调度策略,都是针对"交换技术"的具体实现,而不同策略之间的区别就在于2个问题:交换谁?何时交换?

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2609.html


3. 内存连续分配管理方式

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2610.html


4. 内存非连续分配管理方式

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2611.html


5. 虚拟内存的概念、特征及其实现

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2612.html


6. 请求分页管理方式实现虚拟内存

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2613.html


7. 页面置换算法

本小节学习页面置换算法,本质上就是在学习内存的"交换策略"

进程运行时,若其访问的页面不在内存而需将其调入,但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区。(这和cache的动态更新原理是一样的)
选择调出页面的算法就称为"页面置换算法"。好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或者以后较长时间内不会再访问的页面先调出

0x1: 最佳置换算法(OPT)

最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。这只是一种判断算法的最优标准

最佳置换算法可以用来评价其他算法。假定系统为某进程分配了三个物理块,并考虑有以下页面号引用串:

7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1

进程运行时

1. 先将7, 0, 1三个页面依次装入内存
2. 进程要访问页面2时,产生缺页中断,根据最佳置换算法,选择第18次访问才需调入的页面7予以淘汰
3. 然后,访问页面0时,因为已在内存中所以不必产生缺页中断
4. 访问页面3时又会根据最佳置换算法将页面1淘汰
5. ……依此类推 

可以看到,发生缺页中断的次数为9,页面置换的次数为6

访问页面 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
物理块1 7 7 7 2   2   2     2     2       7    
物理块2   0 0 0   0   4     0     0       0    
物理块3     1 1   3   3     3     1       1    
缺页否  √                      

0x2: 先进先出(FIFO)页面置换算法

优先淘汰最早进入内存的页面,亦即在内存中驻留时间最久的页面。该算法实现简单,只需把调入内存的页面根据先后次序链接成队列,设置一个指针总指向最早的页面。
但该算法与进程实际运行时的规律不适应,因为有的页面虽然是最早被调入内存的,但是一直在被进程访问使用,这是程序的局部性导致的,所以,简单地根据调入内存时间进行"内存交换",可能会带来严重的"换页抖动"

访问页面 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
物理块1 7 7 7 2   2 2 4 4 4 0     0 0     7 7 7
物理块2   0 0 0   3 3 3 2 2 2     1 1     1 0 0
物理块3     1 1   1 0 0 0 3 3     3 2     2 2 1
缺页否          

这里仍用上面的实例,釆用FIFO算法进行页面置换。进程访问页面2时,把最早进入内存的页面7换出。然后访问页面3时,再把2, 0, 1中最先进入内存的页换出。由图FIFO算法的换页次数明显增加了

FIFO算法还会产生当所分配的物理块数增大而页故障数不减反增的异常现象,这是由 Belady于1969年发现,故称为Belady异常。只有FIFO算法可能出现Belady 异常,而LRU和OPT算法永远不会出现Belady异常。

访问页面 1 2 3 4 1 2 5 1 2 3 4 5
物理块1 1 1 1 4 4 4 5     ,5‘ 5  
物理块2   2 2 2 1 1 1     3 3  
物理块3     3 3 3 2 2     2 4  
缺页否      
    1 1 1     5 5 5 5 4 4
物理块2*   2 2 2     2 1 1 1 1 5
物理块3*     3 3     3 3 2 2 2 2
物理块4*       4     4 4 4 3 3 3
缺页否      

Belady现象的原因是FIFO算法的置换特征与进程访问内存的动态特征是矛盾的,即被置换的页面并不是进程不会访问的,因而FIFO并不是一个好的置换算法

0x3: 最近最久未使用(LRU)置换算法

LRU算法是一个被广泛使用和接收的cache调度算法,它的调度思想具有较好的合理性

LRU算法的思想是:选择最近最长时间未访问过的页面予以淘汰,它认为过去一段时间内未访问过的页面,在最近的将来可能也不会被访问。

回到内存交换的总原则:交换谁?何时交换?对于LRU算法来说,这里的评判标准就是"最近最长时间未使用过",如何计算这个值呢?

1. 用一个链表、或者具有链表特征的数据结构来保存数据,取数据时只从头部取,插入数据的时候只从尾部插入,这样,每次数据被使用后就会从头部取出,并插入尾部。这种策略隐含的思想就是越尾部的数据就是越最近被使用的,头部的都是不经常被使用的

2. 为每个页面设置一个访问字段,来记录页面自上次被访问以来所经历的时间,淘汰页面时选择现有页面中值最大的予以淘汰。

这2种算法都能满足LUR的要求,再对上面的实例釆用LRU算法进行页面置换

访问页面 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
物理块1 7 7 7 2   2   4 4 4 0     1   1   1    
物理块2   0 0 0   0   0 0 3 3     3   0   0    
物理块3     1 1   3   3 2 2 2     2   2   7    
缺页否                

进程第一次对页面2访问时,将最近最久未被访问的页面7置换出去。然后访问页面3时,将最近最久未使用的页面1换出。

前5次置换的情况与最佳置换算法相同,但两种算法并无必然联系。实际上,LRU算法根据各页以前的情况,是"向前看"的,而最佳置换算法则根据各页以后的使用情况,是"向后看"的。

LRU性能较好,但需要寄存器和栈的硬件支持。LRU是堆栈类的算法。理论上可以证明,堆栈类算法不可能出现Belady异常。FIFO算法基于队列实现,不是堆栈类算法。

LRU算法编程实践

#include <iostream>
#include "lru.hpp"

using namespace std;

struct stHashInfo
{
    int hints;
    time_t tmodify;
};

int main()
{
    // Create a cache
    typedef plb::LRUCacheH4<int, struct stHashInfo> lru_cache;
    lru_cache cache(5000);

    struct stHashInfo a = {5, 19910726};
    struct stHashInfo b = {8, 19910727};
    struct stHashInfo c = {12, 19910728};
    struct stHashInfo d = {22, 19910729};

    cache[1] = a;
    cache[2] = b;
    cache[3] = c;
    cache[4] = d;

    cache.find(1);
    cache.find(2);
    cache.find(2);
    cache.find(2);
    cache.find(2);
    cache.find(2);
    cache.find(2);
    cache.find(1);
    cache.find(3);

    for (lru_cache::const_iterator it = cache.lru_begin(); it != cache.end(); it++)
    {
        cout << it.key() << " -> hints: " << it.value().hints << " tmodify: " << it.value().tmodify << endl;
    }

    return 0;
}

Relevant Link:

https://code.google.com/p/lru-cache-cpp/

0x4: 时钟(CLOCK)置换算法

LRU算法的性能接近于OPT,但是实现起来比较困难,且开销大;FIFO算法实现简单,但性能差。为了获得一个平衡,操作系统的设计者试图用比较小的开销接近LRU的性能,这类算法都是CLOCK算法的变体

1. 简单的CLOCK算法是给每一帧关联一个附加位,称为使用位
2. 当某一页首次装入主存时,该帧的使用位设置为1
3. 当该页随后再被访问到时,它的使用位也被置为1
4. 对于页替换算法,用于替换的候选帧集合看做一个循环缓冲区,并且有一个指针与之相关联
5. 当某一页被替换时,该指针被设置成指向缓冲区中的下一帧
6. 当需要替换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一帧。每当遇到一个使用位为1的帧时,操作系统就将该位重新置为0
7. 如果在这个过程开始时,缓冲区中所有帧的使用位均为0,则选择遇到的第一个帧替换
8. 如果所有帧的使用位均为1,则指针在缓冲区中完整地循环一周,把所有使用位都置为0,并且停留在最初的位置上,替换该帧中的页(交换是必须要做的)

由于该算法循环地检查各页面的情况,故称为CLOCK算法,又称为最近未用(Not Recently Used, NRU)算法

CLOCK算法的性能比较接近LRU,而通过增加使用的位数目,可以使得CLOCK算法更加高效。在使用位的基础上再增加一个"修改位",则得到改进型的CLOCK置换算法。这样,每一帧都处于以下四种情况之一:

1. 最近未被访问,也未被修改(u=0, m=0)。
2. 最近被访问,但未被修改(u=1, m=0)。
3. 最近未被访问,但被修改(u=0, m=1)。
4. 最近被访问,被修改(u=1, m=1)。

算法执行如下操作步骤:

1. 从指针的当前位置开始,扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一个帧(u=0, m=0)用于替换。
2. 如果第1)步失败,则重新扫描,查找(u=0, m=1)的帧。选择遇到的第一个这样的帧用于替换。在这个扫描过程中,对每个跳过的帧,把它的使用位设置成0。
3. 如果第2)步失败,指针将回到它的最初位置,并且集合中所有帧的使用位均为0。重复第1步,并且如果有必要,重复第2步。这样将可以找到供替换的帧。

改进型的CLOCK算法优于简单CLOCK算法之处在于替换时首选没有变化的页。由于修改过的页在被替换之前必须写回,因而这样做会节省时间

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2614.html
http://blog.csdn.net/ojshilu/article/details/22955741


8. 页面分配策略

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2615.html


9. 页面抖动和工作集

Relevant Link:

http://see.xidian.edu.cn/cpp/html/2616.html

Copyright (c) 2014 LittleHann All rights reserved

时间: 2024-10-10 15:27:27

操作系统内存管理、Cache调度策略学习的相关文章

操作系统 内存管理机制

参考和查阅了一下他人的资料,整理下 虚拟内存.物理内存.Swap分区.页面置换机制等基础知识 虚拟地址空间 与 物理地址空间的关系 虚拟地址由操作系统维护,由MMU可以进行转换,扩大了内存空间分页管理. 大多数使用虚拟存储器的系统都使用一种称为分页(paging)机制. 虚拟地址空间划分成称为页(page)的单位,而相应的物理地址空间也被进行划分,单位是页帧(frame),一个在磁盘,一个在内存,页和页桢的大小必须相同.在32位地址的机器,它的虚拟地址范围从0~0xFFFFFFFF(4G),而这

操作系统内存管理——分区、页式、段式管理

计算存储的层次结构: 当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构,即少量的非常快速.昂贵.易变的高速缓存(cache):若干兆字节的中等速度.中等价格.易变的主存储器(RAM):数百兆或数千兆的低速.廉价.不易变的磁盘.这些资源的合理使用与否直接关系着系统的效率. 1. 内存管理方法 内存管理主要包括虚地址.地址变换.内存分配和回收.内存扩充.内存共享和保护等功能. 2. 连续分配存储管理方式 连续分配是指为一个用户程序分配连续的内存空间.连续分配有单一连续存储管

操作系统--内存管理方式

“碎片的内存”描述一个系统中所有不可用的空闲内存.这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用.这一问题通常都会发生,原因在于空闲内存以小而不连续方式出现在不同的位置.由于分 配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色. internal fragmentation:when memory allocated to a process is larger than requested memory, the differe

操作系统内存管理之 内部碎片vs外部碎片

外部碎片:因为行程持续地被载入与置换,使得可用的记忆体空间被分割成许多不连续的区块.虽然记忆体所剩空间总和足够让新行程执行,却因为空间不连续,导致程式无法载入执行. 内部碎片:发生在以固定长度分割区来进行配置的记忆体中当一个程式载入到固定大小的分割区时,假如程式小于分割区,则剩余的空间将无法被使用,称为内部碎片.利用聚集或分页可以消除外部碎片. "碎片的内存"描述一个系统中所有不可用的空闲内存.这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用.这一问题通常都会发

操作系统---内存管理

一.内存管理概念 1. 存储管理的功能 (1) 内存空间的分配与回收 , 包括内存的分配和共享. (2) 地址转换 : 内存管理配合硬件进行地址转换 , 把逻辑地址转换成物理地址. (3) 内存空间的扩充 : 借助于虚拟存储器或交换覆盖技术来达到扩充内存容量的目的. (4) 内存保护和共享 : 为了避免相互干扰和破坏 , 必须提供保护功能. (5) 虚地址 2. 地址重定位 [程序的装入]   在多道程序设计系统中,可用的内存空间通常被多个进程共享.通常情况下,程序员并不能事先知道在某个程序执行

嵌入式操作系统内存管理有哪几种,各有何特性

嵌入式系统所用到的内存管理机制主要有以下两种: 1.虚拟内存管理机制: 有一些嵌入式处理器提供了MMU,在MMU具备内存地址映射和寻址功能,它使操作系统的内存管理更加方便.如果存在MMU ,操作系统会使用它完成从虚拟地址到物理地址的转换, 所有的应用程序只需要使用虚拟地址寻址数据. 这种使用虚拟地址寻址整个系统的主存和辅存的方式在现代操作系统中被称为虚拟内存.MMU 便是实现虚拟内存的必要条件.虚拟内存的管理方法使系统既可以运行体积比物理内存还要大的应用程序,也可以实现“按需调页”策略,既满足了

操作系统 内存管理(一)

1. 内存管理方法 内存管理主要包括虚地址.地址变换.内存分配和回收.内存扩充.内存共享和保护等功能. 2. 连续分配存储管理方式 连续分配是指为一个用户程序分配连续的内存空间.连续分配有单一连续存储管理和分区式储管理两种方式. 2.1 单一连续存储管理 在这种管理方式中,内存被分为两个区域:系统区和用户区.应用程序装入到用户区,可使用用户区全部空间.其特点是,最简单,适用于单用户.单任务的操作系统.CP/M和 DOS 2.0以下就是采用此种方式.这种方式的最大优点就是易于管理.但也存在着一些问

Linux操作系统 内存管理、用户操作和文件操作

内存管理.用户操作和文件操作 预备知识: 1.Linux系统的内存分为物理内存和虚拟内存.物理内存是指安装在计算机当中的主存储器:虚拟内存是一段虚拟的逻辑上连续的储存空间,虚拟内存是由多个内存碎片组成,只有正在使用的虚拟内存被存放在内存上,对于暂时不使用的虚拟内存空间其实是储存在外存中.虚拟内存空间地址和实际的物理内存空间地址存在某种逻辑上的关系,如果虚拟内存空间地址的内容将被使用,通过逻辑关系可以计算出此部分内容对应的实际物理内存空间,然后将内容加载到内存中.虚拟内存在一定程度上独立于物理内存

操作系统内存管理之 分页与虚存(页表、页框、内存)

一 页面与页表 1 页面 分页存储管理是将作业的逻辑地址划分为一系列同等大小的部分,称为页.并为各页加以编号,每个作业的页的编号都是从0开始的.与之类似,把可用的物理内存也划分为同样大小的连续的部分,称为块或页框.同样为块也进行标号,从0#开始.在为进程分配内存空间时,以页为单位,每个内存中的块存放一页用户作业.只要内存中有足够多的块,这些块可以相邻也可以不相邻,就可以存放整个作业了. 页面的大小对于内存利用和系统开销来说非常重要,页面太大,在作业的最后一页必然会剩余较大不能利用的空间--内碎片