一、内存基本知识

早期内存使用方法

  • 分段 (汇编中使用.section伪指令可以定义一个新的段,在保护模式中使用描述符描述对应的段)
  • 分页(将物理内存分成多个页,每一个段由多个页组成,是最基本的内存管理单元)

1.1 逻辑地址和线性地址

逻辑地址

  • 编译器编译程序时,会为程序生成代码段和数据段,指令或者数据相对于段起始地址的偏移称为逻辑地址。

线性地址

  • CPU加载程序后,会为这个程序分配内存,所分配内存又分为代码段内存和数据段内存。代码段内存的基址保存在CS中,数据段内存的基址保存在DS中。

两者的关系

  • 段基址+逻辑地址 = 线性地址

x86的CPU实模式下,段基址表示的是内存物理地址。而保护模式下段基地存放在描述符中,通过选择子加上逻辑地址可以访问对应的指令或数据,而在ARM处理器中没有这两个概念,他们都被称为虚拟地址。

1.2 虚拟地址转换成物理地址

ARM虚拟地址的结构

  • TTBRx(页表基地址寄存器),里面存放了一级页表的首地址
  • 一级页表里面有4096个页表项(每一个表项里面存储了二级页表的位置,通常也叫做页目录)
  • 通过L1索引可以访问一级页表查找到二级页表的首地址
  • 通过L2索引可以访问二级页表中页起始地址(二级页表项高20位和虚拟地址的低12位组合就是对应的物理地址)

1.3 用户空间和内核空间

Linux系统将程序划分为内核空间和用户空间,内核空间特权级更高。

  • 通常将4G的虚拟地址空间中的0-3GB作为用户空间,3-4GB作为内核空间。

用户申请内存的方式

  • 用户空间调用malloc函数时,使用brk系统调用申请内存,在内核中sys_brk用于处理该系统调用。
  • 用户空间使用的内存是虚拟内存,在堆上申请的内存也是虚拟内存,使用vma管理,包含vma的创建,插入,删除等。
  • 创建vma之后返回对应的虚拟地址,但是无法往里面写入数据,因为此时访问的虚拟地址并不存在,因此会产生一个异常叫做缺页中断。
  • 缺页中断用于建立虚拟地址到物理地址的映射,分配对应的物理内存,并将物理地址写入到页表中。

二、内核中的内存管理模块

匿名页面和 page cache

  • 物理页面可以分为匿名页面 (没有关联任何文件的页面,例如malloc) 和 page cache(关联了具体文件的缓存页面)。

2.1 页面分配器

  • 匿名页面和 page cache的产生依赖于页面分配器,分配的基本单位为一个页框。
  • 页面分配器将页面分配好之后会进行页表管理(包括内核页表和进程页表)。

2.2 SLAB

  • 当用户需要分配的空间只有几个字节的时候,会使用SLAB来进行内存分配。
  • SLAB可以管理特定大小的对象缓存,可以快速的进行分配和回收,而不必每次都需要页面分配器。

2.3 页面回收

  • 当系统内存短缺的时候,将会把不常用的内存页换出到交换区中(page cache 或者匿名页面)。
  • 系统中有一个守护进程,当系统可用内存低于某个警戒线的时候,它将会从LRU链表中查找不常用的内存并回收(系统更加倾向page cache,如果page cache里面是干净的会直接回收,如果是脏的,需要放到交换区中,匿名页表中存储的是进程私有数据,需要放到交换区)。
  • 反向映射机制(reverse map),它可以找到所有映射到某个页面的虚拟地址空间,为页面回收机制而服务,从而断开虚拟地址与物理页面的映射。

2.4 KSM

KSM(Kernel Samepage Merging)用于将两个完全相同的匿名页面进行合并,当进行写操作时候再将其分开,也就是写时复制。

2.5 Huge Page

用于分配较大的内存,通常大于2M就可以使用它,在服务器中比较常见。

2.6 页迁移

内存中的部分页面可以进行迁移(在页面规整和内存热插拔用到了该技术)。

2.7 内存规整

缓解内存碎片化

2.8 OOM

OOM用于去查找内存较多的进程结束运行

04-03 03:06