概述

大部分计算机有两种运行模式:内核态、用户态
软件中最基础的部分是操作系统,操作系统具有硬件的访问权,可以执行机器能够运行的任何指令,运行在内核态。软件的其余部分运行在用户态下。
image.png

内存分成了两个区域:

  • 内核空间,这个内存空间只有内核程序可以访问;
  • 用户空间,这个内存空间专门给应用程序使用;

内存管理

为了进程之间不相互影响,操作系统为每个进程分配独立的一套「虚拟地址」。

  • 我们程序所使用的内存地址叫做虚拟内存地址Virtual Memory Address
  • 实际存在硬件里面的空间地址叫物理内存地址Physical Memory Address)。

操作系统如何管理虚拟地址和物理地址之间的关系呢?
主要有两种方式,分别是内存分段和内存分页

内存分段

将内存分为几个固定的区域,每个区域的大小固定(通常不同),需要加载程序是选择一个闲置且容量足够大的分区进行加载
image.png
优点:
能产生连续的内存空间
缺点:
1:内存碎片
2:内存交换效率低

内存分页

为了解决分段的缺点,就出现了分页。
分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫页(Page)。在 Linux 下,每一页的大小为 4KB。
优点:不再需要一次性都把程序加载到物理内存中,只有在需要用到对应虚拟内存页里面的指令和数据时,再加载到物理内存里面去。(内核的请求分页机制产生缺页异常时调入物理内存)

简单分页:

image.png
缺点:在 32 位的环境下,一个进程的虚拟地址空间有 4GB。假设一个页的大小是 4KB(2^12),就需要4MB空间,100个进程就需要400MB,内存资源宝贵,这个占用了太大空间。

多级页表

image.png
如果使用了二级分页,一级页表就可以覆盖整个 4GB 虚拟地址空间,但如果某个一级页表的页表项没有被用到,也就不需要创建这个页表项对应的二级页表了,即可以在需要时才创建二级页表,基于计算机的局部性原理去节约了空间。把二级分页再推广到多级页表,就会发现页表占用的内存空间更少了,这一切都要归功于对局部性原理的充分应用。
缺点:多级页表虽然解决了空间上的问题,但是虚拟地址到物理地址的转换就多了几次页表的转换,造成时间的开销。于是引入了页表缓存TLB。

Linux内存管理

image.png
linux内核中所有的所有用户态进程使用的都是同一段,且段基地址都是0.
由于段基地址都是0,对于每个进程来说,逻辑地址和线性地址是一样的,同时每个进程的pgd是不一样的,从而保证每个进程之间相互隔离,不同进程的同一虚拟地址映射的物理空间也就不一样了。
(Linux系统中每个进程对应用户空间的pgd是不一样的,但是linux内核 的pgd是一样的。当创建一个新的进程时,都要为新进程创建一个新的页面目录pgd)
Linux的四级页表
image.png
Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),
虽然每个进程都各自有独立的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存

image.png