操作系统对一些基础概念有所了解后,我们可以来关注操作系统底层的一些设计,在掌握了这些特性后,我们才能更好地针对性地编写高性能代码SIMDSIMD, Single Instruction Multlple Data,用一个指令并行地对多个数据进行运算,是CPU基本指令集的扩展。例一处理器的寄存器通常是32位或者64位的,而囲像的一个像素点可能只有8bt,如果一次只能处理一个数据比较浪费空间;此时可以将64位寄存器拆成8个8位寄存器,就可以井行完成8个操作,提升效率。例二SSE指令来用128位寄存器',我们通常将4个32位浮点值打包到128位寄存器中,单个指令可完成4对浮点数的计算,这对于矩阵/向量操作非常友好(除此之外,还有Neon/FPU等寄存器)oat tHhoat loamSIMD井行计算高速缀存一般来说CPU以趄高速运行,而内存速度慢于CPU,硬盘速度慢于内存。当我们把数据加截内存后,要对数据进行一定操作时,会将数据从内存載入CPU寄存器。考虑到CPU读/写主内存速度较慢,处理留使用了高速的缀存(Cache),作为内存到CPU中间的媒介。Cp\L1级存和L2缀存'引入1和し2级存后,CPU和内存之间的将无法进行直接的数据交互,而是需要经过两级缓存'(目前也已出现L3缀存)。① CPU请求数据:如果数据巳经在级存中,则直接从缀存載入寄存器;如果数据不在缀存中(缀存命中失败),则需要从内存读取,井将内存载入缀存中。②CPU写入数据:有两种方案,(1)写入到缀存时同步写入内存(write through cache) (2)仅写入到缀存中,有必要时再写入内存(write-back)为了提高程序性能,则需要尽可能避免级存命中失败,一股而言,遵循尽可能地集中连续访问内存,减少”跳变"访问的原则 (locality ofreference)。这里其实隐含了两个意思,一个是内存空间上要尽可能连续,另外一个是访间时序上要尽可能连续。像节点式的数据结构'的遍历就会差于内存连续性的容器。虚拟内存虚拟内存,也就是把不连续的物理内存'块映射到虚拟地址空间”(vIrtual addross spaco).使内存页对于应用程序来说看起来是连续的。一般而声,出于程序安全性和物理内存可能不足的考虑,我们的程序都会运行在虚拟内存上。这意味着,每个程序都有自己的地址空间,我们使用的内存存在一个虚拟地址和一个物理地址,两者之间需要进行地址翻译。缺页在虚拟内存中,每个程序的地址空间被划分为多个块,每个内存块被称作页,每个页的包含了连续的地址,并且彼映射到物理内存、并非所有页都在物理内存中,当我们访间了不在物理内存中的页时,这一现象称为缺页,操作系统会从磁盘将对应内容装载到物理内存;当内存不足,部分页也会写回磁盘。在这里,我们将CPU,高速缀存和主存视为一个整体,统称为DRAM由于DRAM与磁盘之间的读写也比较耗时,为了提高程序性能,我们依然需要确保自己的程序具有良好的”局部性" -在任意时刻都在一个较小的活动页面上工作。分页当使用血拟内存时,会通过MMU将虚拟地址映射到物理内存,虚拟内存的内存块称为页而物理内存中的内存块称为页框,两者大小一致,DRAM和磁盘之间以页为单位进行交换简单来说,如果想要从虚拟内存翻译到物理地址,首先会从一个TLB (TranslatlonLookaside Buffer)的设备中查找,如果找不到,在虚拟地址中也记录了虚拟页号和偏移量,可以先通过虚拟页号找到页框号,再通过偏移量在对应页框进行偏移,得到物理地址。为了加速这个翻译过程,有时候还会使用多级页表,倒排页表等结构,蛋换算法到目前为止,我们已经接触了不少和“置换”有关的内容:例如寄存器和高速缀存之间,DRAM和磁盘之间,以及TLB的缀存等。这个问题的本质是,我们在有限的空间内存储了一些快速查询的结构,但是我们无法存储所有的数据,所以当查询木命中时,就需要花更大的代价,而所谓置换,也就是我们的快速查询结构是在不断更新的,会随着我们的操作,使得一部分数据被装在到快速查询结构中,又有另一部分数据被卸载,相当于完成了数掘的置换。常见的置换有如下几种:最近未使用置换(NRU)出现未命中现象时,置换最近一个周期未使用的数据,先入先出置换(FIFO)出现未命中现象时,置换最早进入的数据。最近最少使用置换(LRU)出现未命中现象时,置换未使用时间最长的数据。
【瓜分奖池】深入 C++内存管理第三章 第5张插图
【瓜分奖池】深入 C++内存管理第三章 第6张插图