Linux 计算机基础知识必知必会_内存管理

 

基础知识回顾


这部分我们简单回顾一下计算机存储体系、虚拟内存、栈和堆,以及堆内存的管理,这部分内容对理解和掌握内存管理比较重要。

 

存储金字塔


Linux 计算机基础知识必知必会_内存管理_02

 这幅图表达了计算机的存储体系,从上至下依次是:

  • CPU寄存器
  • Cache
  • 内存
  • 硬盘等辅助存储设备
  • 鼠标等外接设备

从上至下,访问速度越来越慢,访问时间越来越长。

你有没有思考过下面2个简单的问题,如果没有不妨想想:

  1. 如果CPU直接访问硬盘,CPU能充分利用吗?
  2. 如果CPU直接访问内存,CPU能充分利用吗?

CPU速度很快,但硬盘等持久存储很慢,如果CPU直接访问磁盘,磁盘可以拉低CPU的速度,机器整体性能就会低下,为了弥补这2个硬件之间的速率差异,所以在CPU和磁盘之间增加了比磁盘快很多的内存。

Linux 计算机基础知识必知必会_物理内存_03

然而,CPU跟内存的速率也不是相同的,从上图可以看到,CPU的速率提高的很快(摩尔定律),然而内存速率增长的很慢,虽然CPU的速率现在增加的很慢了,但是内存的速率也没增加多少,速率差距很大,从1980年开始CPU和内存速率差距在不断拉大,为了弥补这2个硬件之间的速率差异,所以在CPU跟内存之间增加了比内存更快的Cache,Cache是内存数据的缓存,可以降低CPU访问内存的时间。

不要以为有了Cache就万事大吉了,CPU的速率还在不断增大,Cache也在不断改变,从最初的1级,到后来的2级,到当代的3级Cache,(有兴趣看cache历史)

Linux 计算机基础知识必知必会_内存管理_04

三级Cache分别是L1、L2、L3,它们的速率是三个不同的层级,L1速率最快,与CPU速率最接近,是RAM速率的100倍,L2速率就降到了RAM的25倍,L3的速率更靠近RAM的速率。

看到这了,你有没有Get到整个存储体系的分层设计自顶向下,速率越来越低,访问时间越来越长,从磁盘到CPU寄存器,上一层都可以看做是下一层的缓存。

看了分层设计,我们看一下内存。

 

虚拟内存


虚拟内存是当代操作系统必备的一项重要功能了,它向进程屏蔽了底层了RAM和磁盘,并向进程提供了远超物理内存大小的内存空间。我们看一下虚拟内存的分层设计

Linux 计算机基础知识必知必会_linux_05

上图展示了某进程访问数据,当Cache没有命中的时候,访问虚拟内存获取数据的过程。

访问内存,实际访问的是虚拟内存,虚拟内存通过页表查看,当前要访问的虚拟内存地址,是否已经加载到了物理内存,如果已经在物理内存,则取物理内存数据,如果没有对应的物理内存,则从磁盘加载数据到物理内存,并把物理内存地址和虚拟内存地址更新到页表。

有没有Get到:物理内存就是磁盘存储缓存层

另外,在没有虚拟内存的时代,物理内存对所有进程是共享的,多进程同时访问同一个物理内存存在并发访问问题。引入虚拟内存后,每个进程都要各自的虚拟内存,内存的并发访问问题的粒度从多进程级别,可以降低到多线程级别

 

栈和堆


我们现在从虚拟内存,再进一层,看虚拟内存中的栈和堆,也就是进程对内存的管理。

Linux 计算机基础知识必知必会_物理内存_06

上图展示了一个进程的虚拟内存划分,代码中使用的内存地址都是虚拟内存地址,而不是实际的物理内存地址。栈和堆只是虚拟内存上2块不同功能的内存区域:

  • 栈在高地址,从高地址向低地址增长。
  • 堆在低地址,从低地址向高地址增长。

栈和堆相比有这么几个好处

  1. 栈的内存管理简单,分配比堆上快。
  2. 栈的内存不需要回收,而堆需要,无论是主动free,还是被动的垃圾回收,这都需要花费额外的CPU。
  3. 栈上的内存有更好的局部性,堆上内存访问就不那么友好了,CPU访问的2块数据可能在不同的页上,CPU访问数据的时间可能就上去了。

 

堆内存管理


Linux 计算机基础知识必知必会_虚拟内存_07

我们再进一层,当我们说内存管理的时候,主要是指堆内存的管理,因为栈的内存管理不需要程序去操心。这小节看下堆内存管理干的是啥,如上图所示主要是3部分:分配内存块,回收内存块和组织内存块

 在一个最简单的内存管理中,堆内存最初会是一个完整的大块,即未分配内存,当来申请的时候,就会从未分配内存,分割出一个小内存块(block),然后用链表把所有内存块连接起来。需要一些信息描述每个内存块的基本信息,比如大小(size)、是否使用中(used)和下一个内存块的地址(next),内存块实际数据存储在data中。

Linux 计算机基础知识必知必会_内存管理_08

一个内存块包含了3类信息,如下图所示,元数据、用户数据和对齐字段,内存对齐是为了提高访问效率。下图申请5Byte内存的时候,就需要进行内存对齐。

Linux 计算机基础知识必知必会_物理内存_09

释放内存实质是把使用的内存块从链表中取出来,然后标记为未使用,当分配内存块的时候,可以从未使用内存块中有先查找大小相近的内存块,如果找不到,再从未分配的内存中分配内存。

上面这个简单的设计中还没考虑内存碎片的问题,因为随着内存不断的申请和释放,内存上会存在大量的碎片,降低内存的使用率。为了解决内存碎片,可以将2个连续的未使用的内存块合并,减少碎片。

以上就是内存管理的基本思路,关于基本的内存管理,想了解更多,可以阅读这篇文章《Writing a Memory Allocator》,本节的3张图片也是来自这片文章。