!以下内容皆为linux1.0版本之前
初始
分页管理方式。利用页目录和页表结构处理对内存的申请和释放操作
page.s仅包含内存页异常的中断处理过程,对缺页和页写保护的处理
主要分为两种情况处理
- 由于缺页引起的页异常中断,通过调用do_no_page(error_code, address)来处理
- 由写保护引起的页异常,此时调用页写保护处理函数do_wp_page(error_code, address)进程处理
内核页表从物理地址0x1000处开始(紧接着目录空间),共4个页表
每个页表,共1024项,每项4字节,总共占用4K字节
每个进程(除了0 1进程)的页表项都是进程被创建时由内核为其在主内存区申请得到的,每个页表项对应一页物理内存,
在0.11版本中,所有进程都是用一个页目录表,而每个进程都有自己的页表。
经过分段处理,内核代码和数据段长度是16MB,使用了4个页表,且直接位于页目录表后面,然后再经过分页机制变换,被直接一一对应的映射到16MB的物理内存上。
为了使用分页机制,一个32位的线性地址被分为三个部分,分别用来指定一个页目录项、一个页表项和对应物理内存页上的偏移地址
- 页框地址:指定一页内存的物理起始地址
- 存在位P: 确定一个页表项是否可以用于地址转换(如果为0且发出地址转换,则会发出缺页中断异常,即当前这个页未使用)
- 已访问A
- 已修改D
- 读/写位
- 用户/超级用户位
- 如果U/S是0,则R/W不生效
- 如果U/S是1
- R/W是0,那么运行在用户层的代码就只能读页面
- R/W是1,那么就有读写页面
一个系统中可以同时存在多个页目录表,而在某个时刻只有一个页目录表可用(由CPU寄存器CR3来确定)
优化机制
swap
当物理内存不够的时候,将部分暂未使用的内存页换到swap分区,从而释放物理内存以供其他进程使用。
在启动初期会根据swap分区大小来初始化swap缓冲区和swap哈希表。
- 增加了swap_info结构体来记录swap区信息。
- 增加swap_map_handle结构来表示swap条目。
- 在页表项中多了一个SWP_TYPE字段来表示是否在swap区。
mmap
进程可以通过mmap将文件或其它对象映射到进程虚拟地址空间
实现了文件内存映射,为后续的共享内存服务奠定基础
使用场景
- 大文件读写,通过mmap可以利用虚拟内存实现缓存和延迟读写
- 进程间通信,通过共享内存方式更快速和低开销
实现
- 增加新的系统调用mmap和munmap
- 在mm目录下引入mmap.c文件实现映射管理
- 每个内存区通过mm_struct结构表示,链入到mm_slot中
- 通过扩展进程内存 descriptors 来表示mmap区
- 定义全局数组mmap_page_range[]表示已映射内存区间
主要数据结构
- mm_struct 描述一个内存区
- pgd_t 页全局目录
- mm_slot 所有内存区链表
接口调整
kmalloc
提供内核空间的动态内存分配功能,代替直接调用get_free_page等接口的方式,大大简化内核程序中的内存申请
使用场景
- 内核数据结构的动态创建,如信号量、队列等
- 设备驱动程序的内存申请
- 临时性数据结构或缓冲区的分配
实现原理
kmalloc数组指向不同大小的内存池,内存池通过linked list组织空闲内存块
定义kmalloc数组指向每个大小分配的内存池, 使用宏SWITCH_ADDRESS_SPACE切换到内核地址空间
根据大小调用get_free_pages或get_free_page分配
用完后调用free_pages或free_page释放
vmalloc
为内核提供可以分配大于最大物理内存的连续虚拟内存区域,通过页表映射实现虚拟连续,实际物理不连续
使用场景
- 大规模内核数据结构的动态创建,大小超过物理内存
- 需要连续虚拟地址的大内存块
- 映射硬件设备的内存到内核虚拟地址空间
实现原理
VMALLOC_RESERVE 记录vmalloc区信息。vm_struct 描述一块vmlloc区。vmap_area 全局的vmalloc区域。
- 定义全局描述符VMALLOC_RESERVE记录vmalloc区信息
- 初始化时根据物理内存调整vmalloc区大小
- vmalloc函数申请地址,获取空闲页并更新页表
- vfree函数释放地址,回收页表和页面