您当前的位置: 首页 >  操作系统

庄小焱

暂无认证

  • 2浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

操作系统——内存管理

庄小焱 发布时间:2021-09-04 14:12:11 ,浏览量:2

摘要

主要是讲解操作系统的内存的管理技术和虚拟内存技术的实现原理。

内存管理基本的概念

内存也可称为主存,不管硬盘多大、里面存放了多少程序和数据,只要程序运行或者数据要进行计算处理,就必须先将它们装入内存。

 内存的速度还有逻辑上内存和系统的连接方式和结构

https://static001.geekbang.org/resource/image/1b/ed/1b41056cce55b17a2366d7b9dd922aed.jpg

 Cache高速缓存

Cache 中存放了内存中的一部分数据,CPU 在访问内存时要先访问 Cache,若 Cache 中有需要的数据就直接从 Cache 中取出,若没有则需要从内存中读取数据,并同时把这块数据放入 Cache 中。但是由于程序的局部性原理,在一段时间内,CPU 总是能从 Cache 中读取到自己想要的数据。Cache 可以集成在 CPU 内部,也可以做成独立的芯片放在总线上,现在 x86 CPU 和 ARM CPU 都是集成在 CPU 内部的。其逻辑结构如下图所示。

https://static001.geekbang.org/resource/image/47/56/474189597993406a01a2ae171b754756.jpg

Cache 主要由高速的静态储存器、地址转换模块和 Cache 行替换模块组成。

Cache 会把自己的高速静态储存器和内存分成大小相同的行,一行大小通常为 32 字节或者 64 字节。Cache 和内存交换数据的最小单位是一行,为方便管理,在 Cache 内部的高速储存器中,多个行又会形成一组。除了正常的数据空间外,Cache 行中还有一些标志位,如脏位、回写位,访问位等,这些位会被 Cache 的替换模块所使用。

Cache 大致的逻辑工作流程如下

1.CPU 发出的地址由 Cache 的地址转换模块分成 3 段:组号,行号,行内偏移。

2.Cache 会根据组号、行号查找高速静态储存器中对应的行。如果找到即命中,用行内偏移读取并返回数据给 CPU,否则就分配一个新行并访问内存,把内存中对应的数据加载到 Cache 行并返回给 CPU。写入操作则比较直接,分为回写和直通写,回写是写入对应的 Cache 行就结束了,直通写则是在写入 Cache 行的同时写入内存。

3. 如果没有新行了,就要进入行替换逻辑,即找出一个 Cache 行写回内存,腾出空间,替换行有相关的算法,替换算法是为了让替换的代价最小化。例如,找出一个没有修改的 Cache 行,这样就不用把它其中的数据回写到内存中了,还有找出存在时间最久远的那个 Cache 行,因为它大概率不会再访问了。以上这些逻辑都由 Cache 硬件独立实现,软件不用做任何工作软件是透明的。

https://static001.geekbang.org/resource/image/97/bd/976f5cf91bc656e2a876235a5d2efabd.jpg

这是一颗最简单的双核心 CPU,它有三级 Cache,第一级 Cache 是指令和数据分开的,第二级 Cache 是独立于 CPU 核心的,第三级 Cache 是所有 CPU 核心共享的。

下面来看看 Cache 的一致性问题,主要包括这三个方面。

1. 一个 CPU 核心中的指令 Cache 和数据 Cache 的一致性问题。

2. 多个 CPU 核心各自的 2 级 Cache 的一致性问题。

3.CPU 的 3 级 Cache 与设备内存,如 DMA、网卡帧储存,显存之间的一致性问题。

CPU 核心中的指令 Cache 和数据 Cache 的一致性问题,对于程序代码运行而言,指令都是经过指令 Cache,而指令中涉及到的数据则会经过数据 Cache。

所以,对自修改的代码(即修改运行中代码指令数据,变成新的程序)而言,比如我们修改了内存地址 A 这个位置的代码(典型的情况是 Java 运行时编译器),这个时候我们是通过储存的方式去写的地址 A,所以新的指令会进入数据 Cache。但是我们接下来去执行地址 A 处的指令的时候,指令 Cache 里面可能命中的是修改之前的指令。所以,这个时候软件需要把数据 Cache 中的数据写入到内存中,然后让指令 Cache 无效,重新加载内存中的数据。再来看看多个 CPU 核心各自的 2 级 Cache 的一致性问题。从上图中可以发现,两个 CPU 核心共享了一个 3 级 Cache。比如第一个 CPU 核心读取了一个 A 地址处的变量,第二个 CPU 也读取 A 地址处的变量,那么第二个 CPU 核心是不是需要从内存里面经过第 3、2、1 级 Cache 再读一遍,这个显然是没有必要的。在硬件上 Cache 相关的控制单元,可以把第一个 CPU 核心的 A 地址处 Cache 内容直接复制到第二个 CPU 的第 2、1 级 Cache,这样两个 CPU 核心都得到了 A 地址的数据。不过如果这时第一个 CPU 核心改写了 A 地址处的数据,而第二个 CPU 核心的 2 级 Cache 里面还是原来的值,数据显然就不一致了。为了解决这些问题,硬件工程师们开发了多种协议,典型的多核心 Cache 数据同步协议有 MESI 和 MOESI。MOESI 和 MESI 大同小异。

Cache 的 MESI 协议

MESI 协议定义了4种基本状态:M、E、S、I,即修改(Modified)、独占(Exclusive)、共享(Shared)和无效(Invalid)。

1.M 修改(Modified):当前 Cache 的内容有效,数据已经被修改而且与内存中的数据不一致,数据只在当前 Cache 里存在。比如说,内存里面 X=5,而 CPU 核心 1 的 Cache 中 X=2,Cache 与内存不一致,CPU 核心 2 中没有 X。

https://static001.geekbang.org/resource/image/b1/61/b19d638e9a37290c1ea1feebce2d7e61.jpg

2.E 独占(Exclusive):当前 Cache 中的内容有效,数据与内存中的数据一致,数据只在当前 Cache 里存在;类似 RAM 里面 X=5,同样 CPU 核心 1 的 Cache 中 X=5(Cache 和内存中的数据一致),CPU 核心 2 中没有 X。

https://static001.geekbang.org/resource/image/bb/e2/bb1fc473f93089a1414a4e01f888dae2.jpg

 

3.S 共享(Shared):当前 Cache 中的内容有效,Cache 中的数据与内存中的数据一致,数据在多个 CPU 核心中的 Cache 里面存在。例如在 CPU 核心 1、CPU 核心 2 里面 Cache 中的 X=5,而内存中也是 X=5 保持一致。

https://static001.geekbang.org/resource/image/03/b0/030bd3e97c93bdef900abc0c6a72b9b0.jpg

无效(Invalid):当前 Cache 无效。前面三幅图 Cache 中没有数据的那些,都属于这个情况。

最后还要说一下 Cache 硬件,它会监控所有 CPU 上 Cache 的操作,根据相应的操作使得 Cache 里的数据行在上面这些状态之间切换。Cache 硬件通过这些状态的变化,就能安全地控制各 Cache 间、各 Cache与内存之间的数据一致性了。

地址空间

如果要使多个应用程序同时运行在内存中,必须要解决两个问题:保护和重定位。我们来看是如何解决的︰第一种解决方式是用保护密钥标记内存块,并将执行过程的密钥与提取的每个存储字的密钥进行比较。这种方式只能解决第一种问题(破坏操作系统),但是不能解决多进程在内存中同时运行的问题。

还有一种更好的方式是创造一个存储器抽象︰地址空间,就像进程的概念创建了一种抽象的CPU来运行程序,地址空间也创建了一种抽象内存供程序使用。地址空间是进程可以用来寻址内存的地址集。每个进程都有它自己的地址空间,独立于其他进程的地址空间,但是某些进程会希望可以共享地址空间。

内存交换

由于的计算机的实际的物理内存有限,但是的有的程序的是需要大量运行内存来实现的处理的,为了计算机能够运行程序,可以采取的是将程序的必要的数据先加载到内存中,然后在利用内存交换技术,将即将处理的数据添加到内存中,将现在不使用的数据放置在硬盘中。

 刚开始的时候,只有进程A在内存中,然后从创建进程B和进程C或者从磁盘中把它们换入内存,然后在图d中,A被换出内存到磁盘中,最后A重新进来。因为图g中的进程A现在到了不同的位置,所以在装载过程中需要被重新定位,或者在交换程序时通过软件来执行﹔或者在程序执行期间通过硬件来重定位。基址寄存器和变址寄存器就适用于这种情况。

内存紧缩(memory compaction):交换在内存创建了多个空闲区(hole),内存会把所有的空闲区尽可能向下移动合并成为一个大的空闲区。但是这项技术通常不会使用,因为这项技术回消耗很多CPU时间。

当进程被创建或者换入内存时应该为它分配多大的内存。如果进程被创建后它的大小是固定的并且不再改变,那么分配策略就比较简单︰操作系统会准确的按其需要的大小进行分配。

Data segment                                                            Data segment代码段数据段bss段rodata段:栈(stack)堆(heap)

代码段(codesegment/textsegment) :又称文本段,用来存放指令,运行代码的一块内存空间此空间大小在代码运行前就已经确定,内存空间一般属于只读,某些架构的代码也允许可写,在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

数据段(datasegment) :可读可写,存储初始化的全局变量和初始化的static变量,数据段中数据的生存期是随程序持续性(随进程持续性)随进程持续性︰进程创建就存在,进程死亡就消失

bss段(bsssegment) :可读可写,存储未初始化的全局变量和未初始化的static变量bss段中数据的生存期随进程持续性,bss段中的数据—般默认为0。

rodata段:只读数据比如printf 语句中的格式字符串和开关语句的跳转表。也就是常量区。例如,全局作用域中的const int ival = 10,ival存放在 .rodata段;再如,函数局部作用域中的 printf("Hello world %dNn" , c);语句中的格式字符串“Hello world %d\n",也存放在.rodata 段。

栈(stack):可读可写,存储的是函数或代码中的局部变量(非static变量)

栈的生存期随代码块持续性,代码块运行就给你分配空间,代码块结束,就自动回收空间

堆(heap) :可读可写,存储的是程序运行期间动态分配的malloc/realloc的空间,堆的生存期随进程持续性,从malloc/realloc到free一直存在

内存管理技术

位图(bitmap):使用位图方法时,内存可能被划分为小到几个字或大到几千字节的分配单元。每个分配单元对应于位图中的一位,0表示空闲, 1表示占用(或者相反)。一块内存区域和其对应的位图如下:

空闲列表(free lists):另一种记录内存使用情况的方法是,维护一个记录已分配内存段和空闲内存段的链表,段会包含进程或者是两个进程的空闲区域。可用上面的图c 来表示内存的使用情况。链表中的每一项都可以代表一个空闲区(H)或者是进程(P)的起始标志,长度和下一个链表项的位置。

分页技术

大部分使用虚拟内存的系统中都会使用一种分页(paging)技术。在任何一台计算机上,程序会引用使用一组内存地址。当程序执行MOV REG 1000的时候,这条指令时,它会把内存地址为1000的内存单元的内容复制到REG中(或者相反,这取决于计算机)。地址可以通过索引、基址寄存器、段寄存器或其他方式产生。这些程序生成的地址被称为虚拟地址(virtual addresses)并形成虚拟地址空间(virtual address space),在没有虚拟内存的计算机上,系统直接将虚拟地址送到内存中线上,读写操作都使用同样地址的物理内存。在使用虚拟内存时,虚拟地址不会直接发送到内存总线上。相反,会使用MMU(Memory Management Unit)内存管理单元把虚拟地址映射为物理内存地址,像下图这样:

虚拟地址空间由固定大小的单元组成,这种固定大小的单元称为页(pages)。而相对的,物理内存中也有固定大小的物理单元,称为页框(page frames)。页和页框的大小一样。

页表的结构

 保护位(Protection):告诉我们哪一种访问是允许的,最简单的表示形式是这个域只有一位,О表示可读可写,1表示的是只读。

修改位(Modified)和访问位(Referenced):会跟踪页面的使用情况。当一个页面被写入时,硬件会自动的设置修改位。修改位在页面重新分配页框时很有用。如果一个页面已经被修改过(即它是脏的),则必须把它写回磁盘。如果一个页面没有被修改过(即它是干净的),那么重新分配时这个页框会被直接丢弃,因为磁盘上的副本仍然是有效的。这个位有时也叫做脏位(dirty bit),因为它反映了页面的状态。

访问位(Referenced):在页面被访问时被设置,不管是读还是写。这个值能够帮助操作系统在发生缺页中断时选择要淘汰的页。不再使用的页要比正在使用的页更适合被淘汰。这个位在后面要讨论的页面置换算法中作用很大。

虚拟内存技术 CPU虚拟化技术:

CPU虚拟化:在物理机(宿主机)中通过线程或进程这种纯软件方式模拟出假的CPU。通过CPU虚拟化就可以将一个物理CPU发给不同的虚拟机使用,但物理CPU核数要大于虚拟CPU总核数,因为虚拟出来的每颗CPU实际上就是一个线程或者进程。虚拟CPU过多时,需要进行进程/线程切换,比较浪费。CPU虚拟化:总资源=服务器CPU个数*单个CPUx核数kernel*线程(超线程为2,单线程为1)。

全虚拟化技术:为每个VM维护一个影子页表记录虚拟化内存与物理内存的映射关系,VMM将影子页表提交给CPU的内存管理单元MMU进行地址转换,VM的页表无需改动。

半虚拟化技术:采用页表写入法,为每个VM创建一个页表并向虚拟化层注册。VM运行过程中VMM不断管理和维护该页表,确保VM能直接访问到合适的地址。

硬件辅助虚拟化技术:EPT/NPT是内存管理单元MMU的扩展,CPU硬件一个特性,通过硬件方式实现GuestOS物理内存地址到主机物理内存地址的转换,系统开销更低,性能更高。

常用的计算服务架构:openstack Nova: OpenStack是开源的云平台,通过不同的组件提供计算、存储、网络、数据库等多种云服务。其中计算服务由Nova组件提供,通过nova-API与其他组件通信,通过nova-compute对接不同的虚拟层提供计算虚拟化服务。

 

 阿里云ECS 架构:云服务器ECS (Elastic Compute Service)是阿里云提供的基于KVM虚拟化的弹性计算服务,建立在阿里云飞天(Apsara)分布式操作系统上。实现计算资源的即开即用和弹性伸缩。请求的主要调用流程为:OpenAPI、业务层、控制系统、宿主机服务。

 

 腾讯云CVM架构:云服务器CVM (Cloud Virtual Machine)是腾讯提供的基于KVM虚拟化的弹性计算服务,建立在腾讯云分布式资源管理调度系统vStation上。请求的主要调用流程为:API Server、vStation、服务器集群。

 内存虚拟化

内存虚拟化抽象了物理内存,虚拟机每个进程都被赋予一块连续的、超大的虚拟内存空间。

内存复用技术:内存复用指在服务器物理内存一定的情况下,通过综合运用内存复用技术对内存进行分时复用。内存复用技术有:

内存气泡:虚拟化层将较空闲VM内存,分配给内存使用较高的虚拟机。内存的回收和分配由虚拟化层实现,虚拟机上的应用无感知,提高物理内存利用率。

内存交换:将外部存储虚拟成内存给VM使用,将VM上长时间未访问的数据存放到外部存储上,建立映射关系。VM再次访问这些数据是通过映射在与内存上的数据进行交换。

内存共享:VM只对共用的内存(共享数据内容为零的内存页)做只读操作,有写操作时运用,写时复制(VM有写操作时,开辟另一空间,并修改映射)。

 I/O虚拟化

全虚拟化:通过软件模拟的形式模拟IO设备,不需要硬件支持,对虚拟机的操作系统也不需要修改(因为模拟的都是一个常见的硬件网卡,如IntelE1000,主流操作系统一般都自带这些驱动,因此默认情下虚拟机不需要再安装驱动。缺点就是性能差了。

半虚拟化:由Hypervisor提供资源调用接口。VM通过特定的调用接口与Hypervisor通信,完成获取完整I/O资源控制操作。(需修改内核及驱动程序,存在移植性和适用性问题,导致其使用受限。)

Pass-through:Hypervisor直接把硬件PCl设备分配给虚拟独占使用,性能当然好啦。但是浪费硬件设备,且配置复杂,首先需要在hypervisor指定通过PClid方式分配给指定的虚拟机,然后虚拟机再识别到设备再安装驱动来使用。

硬件辅助虚拟化:通过硬件的辅助可以让虚拟机直接访问物理设备,而不需要通过VMM。最常用的就是SR-IOV(Single Root l/OVirtualizmion)单根I/O虚拟化标准,该技术可以直接虚拟出128-512网卡,可以让虚拟机都拿到一块独立的网卡,直接使用I/O资源。

I/O环适配功能

正常我们的I/O分为:

非密集I/O:在一秒钟读的次数很少。

密集l/O:在一秒钟内完成了多次读,但每次读取的内容是少量的。

I/O环适配功能主要用来提升大块(44K以上)多队列(32队列深度以上)类型的IO密集型业务的I/O性能(就是将存储设备资源利用率提高).或者是用户可通过开启I/O环适配功能,提升I/O性能。

网络虚拟化

虚拟化是对所有IT资源的虚拟化,提高物理硬件的灵活性及利用效率。云计算中的计算和存储资源分别由计算虚拟化和存储虚拟化提供,而网络作为IT的重要资源也有相应的虚拟化技术,网络资源由网络虚拟化提供。

网络是由各种设备组成,有传统的物理网络,还有运行在服务器上看不到的虚拟网络。如何呈现和管理它们将是网络虚拟化的首要目标。

将物理网络虚拟出多个相互隔离的虚拟网络,从而使得不同用户之间使用独立的网络资源,从而提高网络资源利用率,实现弹性的网络。VLAN就是一种网络虚拟化,在原有网络基础上通过VLAN Tag划分出多个广播域。网络虚拟化保障我们创建出来的虚拟机可以正常通信、访问网络。

 

 

为什么要采用网络虚拟化呢?

数据中心无法满足部署多台虚拟机,网络架构固定。云计算数据中心满足部署多台虚拟机,网络架构会随虚拟机的迁移改变,满足虚拟机的迁移。

网络虚拟化的目的:节省物理主机的网卡设备资源,并且可以提供应用的虚拟网络所需的L2—L7层网络服务。网络虚拟化软件提供逻辑上的交换机和路由器(L2-L3),逻辑负载均衡器,逻辑防火墙(L4-L7)等,且可以以任何形式进行组装,从而为虚拟机提供一个完整的L2-L7层的虚拟网络拓扑。

物理网络包含的设备

路由器:工作在网络层,连接两个不同的网络。

二层交换机:工作在数据链路层,转发数据。

三层交换机:工作在网络层,结合了部分路由和交换机的功能。

服务器网卡:提供通信服务。

网络虚拟化的特点:

与物理层解耦:接管所有的网络服务、特性和应用的虚拟网络必要的配置,简化这些服务、配置将它们映射给虚拟化层,使用服务的应用只需要和虚拟化网络层打交道。

网络服务抽象化:虚拟网络层可以提供逻辑接口、逻辑交换机和路由器等,并确保这些网络设备和服务的监控、QoS和安全。可以和任意安全策略自由组合成任意拓扑的虚拟网络。

网络按需自动化:通过API自动化部署,一个完整的、功能丰富的虚拟网络可以自由部署在底层物理设施上。通过网络虚拟化,每个应用的虚拟网络和安全拓扑拥有移动性。

多租户网络安全隔离:计算虚拟化使多种业务或不同租户资源共享同一个数据中心资源,但其同时需要为多租户提供安全隔离网络。

虚拟化网卡架构

页面置换算法 最优页面置换算法 最近未使用页面置换算法 先进先出页面置换算法 第二次机会页面置换算法 时钟页面置换算法 最近最少使用页面置换算法 用软件模拟LRU 工作集页面置换算法 工作集时钟页面置换算法

关注
打赏
1657692713
查看更多评论
立即登录/注册

微信扫码登录

0.0415s