要点:
对优化工作来说,内存是最重要的资源。计算机的存储体系是个多级缓存体系。理解并应用缓存是全局算法设计实现和局部代码优化调整的基础。
讨论:
有人说程序优化就是内存的优化,可见内存在优化中的地位。现代计算机的存储体系是个多级缓存体系,离CPU越近,速度越快,容量越小。寄存器是L1 Cache的缓存,L1 Cache是L2 Cache的缓存,L2 Cache是RAM缓存,RAM是更外层存储的缓存。好的算法实现和代码优化就是要让程序尽量跑在缓存上,减少与下层存储的交互。具体来说,有以下的几个要点。
1, 提高缓存的时间局部性。在设计数据结构与算法时,尽量重用计算与缓存。理想的状况是读入的数据对象被重复使用后写回下级存储,而不再被读入缓存。
2, 提高缓存的空间局部性。对读入的数据要尽量按照存储顺序来使用,理想的状况是能全部用完。
3, 提高读写效率。每个缓存都有读写的基本单位。寄存器是一个字(4 bytes),Cache是一个Cache Line(32 bytes),内存是4KB的页。设计合理的数据结构,对齐数据,使得读写能基于缓存的基本读写单位可以有效的减少与下层存储的交互。
4, 最内层循环的优化。最内层的代码如果能全部在寄存器上运算,并最大限度减少与Cache的交互,将大大提高运行效率。通常对复杂的运算,最内层循环是汇编语言证明自身价值的地方。
对现代存储体系来说,最重要的概念就是虚拟存储和Cache。下面我们以XSCALE+Windows CE为例,来简要介绍一下虚拟存储和Cache是如何工作的。
Windows CE下的虚拟存储管理可以简单理解为DISK与RAM间的缓存管理。DISK上
的一部分存储空间被作为页文件(Page file)使用。页文件和实际的文件(如EXE)共同作为DISK的存储,而RAM可以看做是DISK的缓存。对某个进程而言,其在RAM
中的部分就称为工作集(working set)。在虚拟存储中,存储器被划分为4KB的页面,每个页面有三种状态,reserver,commit,和 free。对存储器的使用有两种API,第一种是堆(Heap)的API(我们通常使用的C /C++ RunTime Lib的内存分配都是基于堆的API),第二种是内存映射文件API。这两种API实际上都是基于更底层的虚拟存储的直接API(VirtualAlloc)。当然我们也可以直接操作VirtualAlloc来分配粒度为4KB的页面。
下面我们来考察这样一个流程:
1, OS载入test.exe。
2, Test.exe 调用malloc分配了一个二维数组int Array[4][4]。
3, Test.exe 做了一个操作Array[2][2]=Array[3][3];