分类: LINUX
2014-02-20 15:35:56
=============================================================
内存管理
=============================================================
-------------------------------------------------------------
1 分页
-------------------------------------------------------------
1.1 CR3存放正在使用的页目录的物理地址
1.2 CR0的PG标志表示是否启用分页机制
1.3 pgd页全局目录
1.4 内核页表
1.4.1 内核维持一组自己使用的页表,在主内核页全局目录(init_mm.pgd)中,主内核页全局目录保存于swapper_pg_dir全局变量中
1.4.2 分两大段
1.4.2.1 映射低端内存<896M
1.4.2.2 映射高端内存896M+128M
1.5 线性地址转换(线性地址和物理地址)
1.5.1 内核态__pa,__va
1.5.2 用户态必须通过进程各级页表进行转换
页表项中存放的是物理地址,由MMU硬件直接使用。内核中如果需要使用相关页表项内容(比如进行地址转换),需要进行PA->VA的转换,比如:
点击(此处)折叠或打开
2.1 GDT全局描述符表(存放段描述符)
2.1.1 每个CPU一个
2.1.2 包含18个段描述符:内核、用户代码和数据段,TSS段,等
2.1.2.1 linux中内核、用户代码和数据段基址都是0,相当于没有启用分段
2.1.2.2 TSS,任务状态段,包含任务运行状态信息,如各寄存器(如SP)信息,在任务切换时使用
2.2 LDT
2.2.1 Linux中通常不使用,内核中定义了一个缺省的LDT供大多数进程共享default_ldt
2.3 内核代码段固定(32位为例):0xc0000000+0x100000
-------------------------------------------------------------
3 进程地址空间
-------------------------------------------------------------
3.1 每个进程有自己独立的页表(页目录)
3.2 0-3G的地址空间映射不同,但所有进程的3-4G的地址空间映射是相同的(因为内核地址空间是共享的),其页目录、页表相同,页目录中大于0xc0000000的线性地址对应的页目录项等于主内核页全局的相应表项
3.3 VMA
-------------------------------------------------------------
4 内存分配
-------------------------------------------------------------
4.1 内核态
4.1.1 按页分配
4.1.1.1 alloc_page,返回page指针
4.1.1.2 get_free_page返回线性地址
4.1.1.2.1 调用alloc_page
4.1.1.2.2 不能用于分配高端内存,因为内核态中高端内存,不能直接访问,没有直接对应的线性地址
4.1.1.2.1 只能从低端内存中分配,低端内存中的物理内存,通过偏移直接映射
4.1.1.3 vmalloc,非连续内存区分配
4.1.1.3.1 线性地址从896M+8M开始
4.1.1.3.2 每个vmalloc取由4k分割
4.1.1.3.3 最终调用alloc_page分配页,分配后需要修改内核页表对新分配的页进行地址映射,使vmalloc区对应的线性地址映射到高端内存(或其他zone内存)
4.1.1.3.4 通常从高端内存分配
4.1.1.4 高端内存分配,由内核地址空间中的896M开始的128M(默认,可配置)线性映射地址
4.1.1.4.1 vmalloc(最主要的方式)
4.1.1.4.2 永久和临时映射kmap
4.1.1.4.3 固定映射
4.1.2 小于页大小的空间分配
4.1.2.1 kmalloc
4.1.2.2 slab(kmem_cache_alloc)
4.2 用户态
4.2.1 malloc或mmap
4.2.1.1 最终进入内核,通过alloc_page(或get_free_page)分配
4.2.1.1.1 修改页表进行地址映射
4.3 内存分配实质只是在伙伴系统或slab中查找可用的page或结构
4.3.1 系统中所有的物理内存按页组织
4.3.2 所有可用内存由BIOS识别,并通过e820表提供给内核
4.3.3 所有物理内存对应的页(page结构)在系统初始化时就已经分配好了,存放于mem_map全局数组中
4.3.3.1 pfn页框号,按物理内存顺序组织,pfn作为索引的mem_map[pfn]可以得到相应的page结构指针
4.3.3.2 相反,通过page结构指针也可以得到相应的物理地址page-mem_map(页框号,pfn)<
4.3.4 内存分配后,通常只是得到相应的page结构,需要将其映射到线性地址空间中,才能使用
4.3.4.1 内核态映射
4.3.4.1.1 低端内存直接通过偏移映射,内核可直接访问
4.3.4.1.2 高端内存需要通过128M的地址空间映射(间接映射),三种方式
4.3.4.1.2.1 高端内存映射时修改内核页表
4.3.4.1.2.2 理论上,当进程修改3-4G的地址空间映射时,应该需要修改相应的页表,而且应该需要将相应修改同步到所有进程的页表中去,但是如果这样的话就太麻烦了。内核利用了主内核也全局目录,采用 了延迟的方式,在需要对3-4G地址空间进程重新映射时,只修改内核页表,然后在进程访问相应线性地址时,发生缺页异常,在缺页异常中判断内核页表中是否有相应的表项,如果有则将其拷贝到进程的页表中
4.3.4.1.2.2.1 通常是vmalloc和vfree时才需要重新映射内核地址空间和修改内核页表,因为内核中分配内存的其他方式(alloc_page,get_free_page,slab的分配接口等)都是从低端内存中分配内存,低端内存的线性地址都只是通过PAGE_OFFSET的偏移进行映射的,是固定的,是不需要重新映射的
4.3.4.2 用户态映射
4.3.4.2.1 通过页表映射