树莓派上的三种电子元件都有存储数据的功能:CPU缓存、内存和 SD卡储存。

目录

分级存储

简介

三种元件的速度和容量各不相同。存储元件 的容量和速度是个矛盾。为了兼顾性能和成本,计算机大多采取分级存 储的形式,从而让不同速度的存储元件协同工作。分级存储的设计,兼 顾了读取速度、存储容量和计算机的稳定性。如下图所示。

类别 大小 访问速度排序 持久
cpu 一级缓存 32kb 1
cpu 二级缓存 512kb 2
内存 1g 3
sd卡 4g以上 4

缓存

计算机把最快的存储元件用在最繁忙的地方。

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

由于造价昂贵,CPU缓存的容量不大。当CPU需要读写某个内存地址时,它会先检查该内存地址的数据是否已经存在于某条缓存记录(Cache Entry)中。如果缓存记录中的内存地址信息和CPU寻址信息相符,那就说明数据已经缓存了,这种情况叫作缓存命中(Cache Hit)。

CPU会直接读写缓存中的目标记录,速度会比读写内存快很多。如果 CPU想要读写的数据不在缓存中,就是缓存缺失(Cache Miss),那么缓存会增加一条新的缓存记录,把内存地址的数据加载到该缓存记录中。CPU随后从缓存中读写数据。出于成本的原因。我们不可能把计算机的全部数据放在CPU缓存中。缓存中无法容纳的数据,只能存放于内存和SD卡这样速度较慢的存储空间中。

既然这样,CPU缓存必须有一个策略,决定把哪些数据放在缓存中。为了应对缓存缺失的情况,缓存必须增加新的缓存记录。如果缓存已经没有空余的空间,则必须选择替换缓存中的一个记录。这条已经存在的缓存记录被称为牺牲者(Victim),新的缓存记录会被放在牺牲者所在的位置。 选择牺牲者的常见的方法有4种。

  1. 最少使用(LFU,Least Frequently Used)的数据。
  2. 最久没有使用(LRU,Least Recently Used)的数据。
  3. 最早被缓存(FIFO,First-In First-Out)的数据。
  4. 随机替换(Random Replacement)。

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

上面对缓存工作流程的描述只是基于一层缓存的。实际上,树莓派中存在两级缓存。一级缓存L1的读写速度高于二级缓存L2,而二级缓 存L2的速度又高于内存的速度。沿用已经讨论过的工作流程,在一级缓存和二级缓存之间、二级缓存和内存之间进行数据交互。两级缓存夹在 CPU到内存之间,弥补了两者的速度差异,让计算机的数据读写变得更 有效率。 类似的缓存技术在计算机中使用很广。除了数据,CPU还会缓存来 自内存的指令及分页记录。很多技术的实现都离不开缓存带来的效率,以虚拟内存为例,虚拟内存技术可以实现很多功能,比如构建进程空间 和实现内存共享,但虚拟内存不是免费的。内核必须记录虚拟内存页和 物理内存页的对应关系,并花费额外的CPU时间进行地址转换。利用缓 存技术把分页记录放在CPU内部的高速元件上,可以有效解决寻址的效率问题。

页交换

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

长期以来,计算机运行中一直面临一个恼人的问题:进程所需的空 间有可能超过计算机的物理内存空间。这个时候计算机就无法运行对应 程序了。例如,一个内存为1GB的树莓派,它的进程数据需要占据2GB 的空间,那么树莓派就无法执行这个操作。虽然内存空间在不断增加, 但程序所需空间也越来越庞大,内存空间成了程序发展的屏障。而在计 算机上,能提供足够大存储空间的,只能是外部存储器。由于内存和外 部存储器的速度差异非常大,因此我们需要一种技术,在把外部存储器 空间变成内存空间的同时,还能一定程度上保证计算机运行的效率。 虚拟内存可以把一部分的外部存储器空间转换成内存空间,让应用 程序可以虚拟地增加内存大小。这一技术的关键在于页交换(Page Swap)。所谓的页交换,就是进程空间和外部存储空间以页为单位交 换数据。虚拟内存是一套管理数据和数据地址的方法,也可以用于外部 存储空间的管理。操作系统可以把一部分外部存储空间划分成页,称为 交换空间(Swap Space)。操作系统按照管理内存的方式来管理交换空 间。物理内存和交换空间加在一起大大拓展了实际存储容量。 当然,外部存储器读写速度慢的瓶颈始终存在。为了保证读写效 率,应用程序只用在物理内存中的虚拟内存。当程序访问的数据恰好位 于交换空间时,内核就会启动页交换,把交换空间的页转移到物理内存 中,随后内核把分页对应到该物理内存位置,并通知应用程序继续进行 数据操作。这样,程序访问的虚拟内存地址就指向了物理内存中的数据 位置。对于应用程序来说,它只是根据虚拟内存地址进行操作,整个过 程都不需要知道内核的幕后动作。 具体来说,内核记录着虚拟内存的对应关系。当应用进程访问虚拟 内存页时,内核会根据对应关系,知道物理页存在内存还是外部存储器 中。如果该页存在外部存储器,内核则会让程序短暂休息,然后将外部 存储器中这一页的内容放入物理内存中。如果内存空间已满,那么虚拟 内存要选择把内存中的一页移出交换空间,从而为要进入内存的页准备 好空间。在这个过程中,内存和外部存储器交换了一页,这也是页交换 得名的原因。移出内存的页充当了牺牲者。其实页交换和CPU的缓存替 换非常相似,选择牺牲者的方法也和缓存的替换策略一样。Linux操作 系统使用了一种类似于LRU的策略,即选择最久没有使用的分页作为牺 牲者。