树莓派开始,玩转Linux28:分级存储

树莓派开始,玩转Linux28:分级存储

树莓派上的三种电子元件都有存储数据的功能:CPU缓存、内存和SD卡储存,如表所示。三种元件的速度和容量各不相同。存储元件的容量和速度是个矛盾。为了兼顾性能和成本,计算机大多采取分级存储的形式,从而让不同速度的存储元件协同工作。分级存储的设计,兼顾了读取速度、存储容量和计算机的稳定性。

树莓派3B型的各项储存器指标:
在这里插入图片描述
1.CPU缓存:

计算机把最快的存储元件用在最繁忙的地方。CPU是树莓派执行程序的核心,我们编写的程序和需要处理的各种数据都要加载到CPU中才能执行。除了CPU频率外,CPU对数据的访问速度是决定其运行速度的一大重要因素。因此,CPU上配置了两级的高速缓存,来让CPU更快地提取到数据。

由于造价昂贵,CPU缓存的容量不大。当CPU需要读写某个内存地址时,它会先检查该内存地址的数据是否已经存在于某条缓存记录(Cache Entry)中。如果缓存记录中的内存地址信息和CPU寻址信息相符,那就说明数据已经缓存了,这种情况叫作缓存命中(Cache Hit)。CPU会直接读写缓存中的目标记录,速度会比读写内存快很多。如果CPU想要读写的数据不在缓存中,就是缓存缺失(Cache Miss),那么缓存会增加一条新的缓存记录,把内存地址的数据加载到该缓存记录中。CPU随后从缓存中读写数据。

出于成本的原因。我们不可能把计算机的全部数据放在CPU缓存中。缓存中无法容纳的数据,只能存放于内存和SD卡这样速度较慢的存储空间中。既然这样,CPU缓存必须有一个策略,决定把哪些数据放在缓存中。为了应对缓存缺失的情况,缓存必须增加新的缓存记录。如果缓存已经没有空余的空间,则必须选择替换缓存中的一个记录。这条已经存在的缓存记录被称为牺牲者(Victim),新的缓存记录会被放在牺牲者所在的位置。

以LRU策略为例,学习缓存的替换策略。如果CPU采用了LRU策略,那么CPU为每个缓存记录增加一个计数。当CPU读缓存时,LRU会把命中记录的计数清零,而其他记录的计数增加1。如果一条记录长期没有被读取,那么它的计数就会越来越大。在选择牺牲者时,CPU缓存会选择计数最大的记录作为牺牲者。

上面对缓存工作流程的描述只是基于一层缓存的。实际上,树莓派中存在两级缓存。一级缓存L1的读写速度高于二级缓存L2,而二级缓存L2的速度又高于内存的速度。沿用已经讨论过的工作流程,在一级缓存和二级缓存之间、二级缓存和内存之间进行数据交互。两级缓存夹在CPU到内存之间,弥补了两者的速度差异,让计算机的数据读写变得更有效率。

类似的缓存技术在计算机中使用很广。除了数据,CPU还会缓存来自内存的指令及分页记录。很多技术的实现都离不开缓存带来的效率,以虚拟内存为例,虚拟内存技术可以实现很多功能,比如构建进程空间和实现内存共享,但虚拟内存不是免费的。内核必须记录虚拟内存页和物理内存页的对应关系,并花费额外的CPU时间进行地址转换。利用缓存技术把分页记录放在CPU内部的高速元件上,可以有效解决寻址的效率问题。

2.页交换:

借用缓存技术,我们弥补了CPU和内存之间的速度差。而虚拟内存技术,则可以把外部存储器空间当作内存用。其实虚拟内存诞生之初,正是为了实现这一目的。

长期以来,计算机运行中一直面临一个恼人的问题:进程所需的空间有可能超过计算机的物理内存空间。这个时候计算机就无法运行对应程序了。例如,一个内存为1GB的树莓派,它的进程数据需要占据2GB的空间,那么树莓派就无法执行这个操作。虽然内存空间在不断增加,但程序所需空间也越来越庞大,内存空间成了程序发展的屏障。而在计算机上,能提供足够大存储空间的,只能是外部存储器。由于内存和外部存储器的速度差异非常大,因此我们需要一种技术,在把外部存储器空间变成内存空间的同时,还能一定程度上保证计算机运行的效率。

虚拟内存可以把一部分的外部存储器空间转换成内存空间,让应用程序可以虚拟地增加内存大小。这一技术的关键在于页交换(PageSwap)。所谓的页交换,就是进程空间和外部存储空间以页为单位交换数据。虚拟内存是一套管理数据和数据地址的方法,也可以用于外部存储空间的管理。操作系统可以把一部分外部存储空间划分成页,称为交换空间(Swap Space)。操作系统按照管理内存的方式来管理交换空间。物理内存和交换空间加在一起大大拓展了实际存储容量。

当然,外部存储器读写速度慢的瓶颈始终存在。为了保证读写效率,应用程序只用在物理内存中的虚拟内存。当程序访问的数据恰好位于交换空间时,内核就会启动页交换,把交换空间的页转移到物理内存中,随后内核把分页对应到该物理内存位置,并通知应用程序继续进行数据操作。这样,程序访问的虚拟内存地址就指向了物理内存中的数据位置。对于应用程序来说,它只是根据虚拟内存地址进行操作,整个过程都不需要知道内核的幕后动作。

具体来说,内核记录着虚拟内存的对应关系。当应用进程访问虚拟内存页时,内核会根据对应关系,知道物理页存在内存还是外部存储器中。如果该页存在外部存储器,内核则会让程序短暂休息,然后将外部存储器中这一页的内容放入物理内存中。如果内存空间已满,那么虚拟内存要选择把内存中的一页移出交换空间,从而为要进入内存的页准备好空间。在这个过程中,内存和外部存储器交换了一页,这也是页交换得名的原因。移出内存的页充当了牺牲者。其实页交换和CPU的缓存替换非常相似,选择牺牲者的方法也和缓存的替换策略一样。Linux操作系统使用了一种类似于LRU的策略,即选择最久没有使用的分页作为牺牲者。

3.交换空间:

本节介绍交换空间的具体实施方法。交换空间有交换分区和交换文件两种形式。交换分区就是用一个独立的存储器分区作为交换空间,和一般的磁盘分区不同,它没有文件系统,完全以页的方式进行管理。交换文件是文件系统中的一个特殊文件,它占据的空间以页的方式进行管理,作为交换空间。我们可以使用下面的命令查看交换空间:
在这里插入图片描述
输出结果如下:
在这里插入图片描述
每一行列出的都是系统正在使用的交换空间。Type字段表明该交换空间是一个分区而不是文件,通过Filename可以知道交换分区是磁盘sda5。Size字段表明磁盘大小,单位是KB,Used字段是表示有多少交换空间被使用。Priority字段表示Linux系统的交换空间使用优先级。如果在Linux系统中挂载两个或更多具有相同优先级的交换空间,那么Linux会交替使用。如果两个交换空间正好位于两种设备上,那么这种交替使用的方式可以提升交换性能。用mkswap命令把分区/dev/hdb1变成交换分区:

在这里插入图片描述
用swapon命令激活交换分区:
在这里插入图片描述
再次确认/dev/hdb1已经加入交换空间:
在这里插入图片描述
Linux也支持交换文件形式的交换空间。在Linux环境中,创建文件比创建分区简单得多,可以用dd命令创建一个1GB的文件,比如:
在这里插入图片描述
交换文件就是/var/swapfile。选项count说明了文件大小,即1048576KB。创建文件后,就可以用mkswap调用交换文件。
在这里插入图片描述
激活交换文件,让交换文件成为可以使用的交换空间。
在这里插入图片描述

4.外存的缓存与缓存:

通过页交换技术,我们用外部存储器弥补了内存容量的不足,但页交换毕竟只发生在外存的交换空间。对于文件系统管理形式的其他分区,我们一样要解决内存和外存互动的问题。内存和外存速度差异巨大。因此,操作系统读写文件时,必须要想办法弥补两者之间的速度差异。

CPU缓存技术可以弥补这种差异。如果内存中的部分空间可以用来缓存常用的文件系统数据,就可以大大减少外存的访问量。这种技术就是页缓存(Page Cache),页缓存和CPU缓存非常类似。在读取外存中的文件时,文件的数据会先存在内存中未使用的页上。此后,如果需要读取相同的数据,那么CPU可以直接从内存提取。当内存中可用于页缓存的空间填满时,计算机使用类似于LRU的策略选择牺牲者,用新的文件数据来替换掉缓存页。通过free命令,可以查看内存中页缓存空间的大小。

在这里插入图片描述
在返回结果中,cached那一列说明了页缓存空间的大小。除了页缓存,内存还会在其他场景下使用缓存思想。比如,内存中会缓存文件系统的inode。读取文件的inode,是获得文件数据的第一步。对于频繁读写的文件,如果能在内存中缓存inode,那么文件的读写效率也会大大提高。

我们再来看另一种思想,即缓冲读写的思想。举一个例子,进程往一个文件中写入15个字符"Vamei loves RPI",进程可以每次从内存中拿一个字符写入外存。由于外存写入速度慢,那么在外存完成这个字符写入的过程中,进程都是闲置的。当然,进程可以进入阻塞状态,把CPU出让给其他的进程。然而,进程状态切换需要付出代价。此外,外存写入字符前需要进行一些准备动作,比如找到写入块位置。分开写入15个字符,外存就要重复15次准备动作。

缓冲的目的就是在内存中收集多个待写入的字符,再一次性写入外存。这一方面减少了进程切换状态的次数。另一方面,外存可以共用同一套准备动作,从而减少开销。内存为进程打开的文件保留缓冲区(Buffer),用于收集待写入文件的文本。缓冲区采用先进先出的策略,先写入的字符会被先取出。在刷新(Flush)缓冲区时,缓冲区中存储的文本会按照先后次序一次性写入外存。操作系统的内核提供了缓冲区。因此,很多时候用write()系统写一个字符到文件,字符并没有真正存入文件。缓冲区的写入与刷新,如图所示。
在这里插入图片描述
缓冲区的写入与刷新,上图:

计算机会在多个条件下刷新缓冲区。
· 缓冲区填满了数据。
· 文件关闭。
· 进程终结。
· 文本中出现换行符。
· 该文件出现数据读取。
Linux内核中内置了缓冲读写的功能。不过,鉴于缓冲是一种简单而有效的策略,应用程序也可以自己在进程空间中安排缓冲区,来把多次操作合并成一次操作。事实上,C标准库中的标准IO函数,就负责在读写过程中管理进程空间的缓冲区。IPC和网络通信也经常用到相似的缓冲策略,以提高通信效率。

本章综合叙述了分级存储策略。计算机是一个多组件合作的整体,这些组件在性能上各有千秋,我们必须采用一定的方法来让它们合作,扬长避短,让各个组件发挥最大效率。在最近流行的AI集群和超级云平台上,经常能看到缓存和缓冲的应用,可见操作系统的经典设计历久弥新。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值