虚拟地址(线性地址)
逻辑地址:每一个逻辑地址都由一个段标示符和段偏移组成。
线性地址:也叫虚拟地址,在32位系统下,每个进程会虚拟出4G内存,其中0×00000000 到 0xBFFFFFFF是用户进程空间,
0xC0000000 到 0xFFFFFFFF是内核进程空间。
物理地址:实际的内存地址
逻辑地址 ----(段表)—> 线性地址 — (页表)—> 物理地址
逻辑地址是段标识+段内偏移量的形式,MMU(内存管理模块)通过查询段表,可以把逻辑地址转化为线性地址。
逻辑地址是相对于应用程序而言的
段寄存器(找到逻辑地址)
intel处理器有两种方式进行地址转换:实模式、保护模式。
段寄存器的唯一目的是为了存放段选择符。分别为cd,ss,ds,es,fs和gs六个。
六个寄存器有三个有特殊的用途:
cs:代码段寄存器,指向包含程序指令的段,其中包含一个两位的字段,用以指明CPU的当前特权(CPL),0表示最高级,3表示最低级。
分别称之为内核态和用户态。
ss:栈段寄存器,指向当前程序栈的段
ds:数据段寄存器,指向静态数据或全局数据段。
Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便地访问内存,更确切地说是访问虚拟内存。
既然每个进程都有一个这么大的地址空间,那么所有进程的虚拟内存加起来,自然要比实际的物理内存大得多。所以,并不是所有的虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才分配物理内存,并且分配后的物理内存,是通过内存映射来管理的。
内存映射,其实就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关系,如下图所示:
页表(存储页)
页通常是 4 KB 大小,物理内存与虚拟内存的映射关系
通过MMU查询页表
如果页表未查到地址,产生断页中断
TLB快表(页表的高速缓存)
页的大小只有 4 KB ,导致的另一个问题就是,整个页表会变得非常大。比方说,仅 32 位系统就需要 100 多万个页表项(4GB/4KB),才可以实现整个地址空间的映射。为了解决页表项过多的问题,Linux 提供了两种机制,也就是多级页表和大页(HugePage)
再看大页,顾名思义,就是比普通页更大的内存块,常见的大小有 2MB 和 1GB。大页通常用在使用大量内存的进程上,比如 Oracle、DPDK 等。
虚拟内存空间分布
参考:
https://blog.youkuaiyun.com/jinking01/article/details/107098437