相比CPU
,内存(Memory
)是更复杂的硬件资源,原因在于操作系统对两种资源的处理方式不一样。虽然CPU
和Memory
都可被多个进程分时共享,但共享的代价差别很大,这在很大程度上影响了用户对两种资源的使用。
操作系统的内存魔法
为了回答用户关于内存使用的问题,我们需要先了解操作系统的内存管理机制。
内存分层体系
冯诺依曼计算机体系结构的要点是存储程序计算,其中内存承载程序指令和数据,是关键的性能影响因素。现代操作系统采用内存分层体系,利用程序执行和内存访问的局部性原理最大化高速内存设备的利用率,优化系统整体性能。下图展示了内存分层体系结构:
这个体系中各级存储设备的性能差别有多大呢?我们祭出一组Google
大牛Jeff Dean
在演讲中公布的性能数字:
从上面的性能数字不难推测,如果我们想办法将最有可能被马上访问的热数据加载到内存,将冷数据存储在相对低速设备中,可以在保持现有成本的前提下最大化用户的性能体验。这就是内存分层体系的指导思想。这个思想暗含的前提是计算机程序运行具有局部性特征。什么是局部性呢?通俗的说就是刚刚执行过的程序指令很大概率被再次运行,刚被访问过的内存地址很大概率又会被访问。在这个假定下,操作系统将很久没有被访问的数据从内存交换到硬盘上,释放出内存空间承载访问频率高的数据,实现了硬盘级别的成本和内存级别的性能。
为了实现这个策略,操作系统采用了虚实策略, 即将内存分为虚拟内存和物理内存。程序猿在C、C++、Java中malloc
或者new
分配的都是虚拟内存,是一个逻辑地址区域,并没有物理内存与之对应。这些区域只要不访问,就不会给它们映射物理内存。一旦程序访问未被映射的虚拟内存区域,就会触发硬件的缺页中断page fault
,陷入到操作系统内核。操作系统分配需要的物理内存,和进程的虚拟地址对应起来。这样程序猿意义上的内存真正与机器物理内存对应上了。记录虚拟地址与物理地址映射的内存区域叫做页表(page table
),它被CPU
硬件的内存管理单元(MMU
)引用。MMU
决定着虚拟地址对应的物理地址是否存在或者有效,并触发缺页中断,让操作系统介入处理。
虚实内存映射是策略的第一个方面,解决动态分配问题。操作系统还需要解决内存的释放和回收问题。如果物理内存不够了,操作系统会通过策略或算法搜索不经常访问的物理页面,或者最近不会访问的物理页面,将该物理内存区域上的数据写到硬盘上的交换区域(swap
)。然后操作系统修改页表映射记录,说明该虚拟地址区域对应的数据存在硬盘的具体位置。这样物理页面就回收给其它进程或者进程的其它虚拟地址区域使用。操作系统管理所有