页表

linux通过虚拟内存实现多进程内存之间的隔离,虚拟内存通过页表映射到虚拟内存,页表一共有4级 PGD -> PUD -> PMD -> PTE -> PAGE, 每一级页表的大小为一个page, 一个page大小为 1 << PAGE_SHIFT , 通常PAGE_SHIFT为12, 也就是一个PAGE为4096字节,每一个page entry为一个word,8 byte,这样一个页表也就是512个entry

虚拟内存地址

我们指到物理地址是有限的,一台物理机64G内存,如果不超卖那就是64G,但是虚拟内存可以认为是无限的,为了将虚拟地址映射到物理地址,一个页表显然不够,所以就需要多级页表,每个页表512个entry,所以最大虚拟内存是512 512 512 512 4096 = 256T的内存,虚拟内存地址被为了5块,每一块都代表着在页表中的索引,指向的是下一级页表的地址
how virtual memory map to physical memory - 图1

  1. #define PAGE_SIZE (1UL << PAGE_SHIFT)
  2. #define PUD_SIZE (1UL << PUD_SHIFT)
  3. #define PMD_SIZE (1UL << PMD_SHIFT)
  4. #define PGDIR_SIZE (1UL << PGDIR_SHIFT)

每个块都代表着在页表中的索引,比如,一个虚拟地址 virtual_address 我们要找到对应的物理页要如何找?

  • 首先根据 PGDIR_SHIFT 找到pgd_offset
  • pgd_offset = virtual_address >> PGDIR_SHIFT
  • 通过pgd_offset在pgd table中找到下一级 pud的地址
  • 通过PUD_SHIFT 计算 pud_offset
  • pud_offset = virtual_address >> PUD_OFFSET
  • 通过pud_offset在pud table中找到下一级 pmd页表的地址
  • 通过PMD_SHIFT 计算 pmd_offset
  • pmd_offset = virtual_address >> PMD_SHIFT
  • 通过pmd_offset在pmd table中找到终极 PTE (page table entry)的地址
  • 通过PTE_OFFSET计算pte_offset
  • pte_offset = virtual_address >> PTE_SHIFT
  • 通过pte_offset在pte中找到 最终physical page的地址
  • 最后通过 offset within page找到物理page中对应的地址

.

TLB

可以看到从虚拟地址到物理地址需要通过很多步骤才能找到,所以为了加速这个过程,出现了TLB (translation lookaside buffer),可以看做是一个hashmap,直接将虚拟地址映射成物理地址