目录
物理内存管理
页表设计
物理内存管理
如果磁盘上的内容加载到物理内存上,每次io都会按照4kb的方式进行加载(可能不同版本系统有些区别)。所以我们的物理内存上的内容也是4个字节进行管理的。
而每个页框都需要我们进行管理。所以自然物理内存就会对页框进行先描述,再组织。物理内存就有struct page[]这个数组来管理所有的页框了。
struct page {unsigned long flags;union {struct {/* 换出⻚列表,例如由zone->lru_lock保护的active_list */struct list_head lru;/* 如果最低为为0,则指向inode* address_space,或为NULL* 如果⻚映射为匿名内存,最低为置位* ⽽且该指针指向anon_vma对象*/struct address_space* mapping;/* 在映射内的偏移量 */pgoff_t index;/** 由映射私有,不透明数据* 如果设置了PagePrivate,通常⽤于buffer_heads* 如果设置了PageSwapCache,则⽤于swp_entry_t* 如果设置了PG_buddy,则⽤于表⽰伙伴系统中的阶*/unsigned long private;};struct {/* slab, slob and slub */union {struct list_head slab_list;/* uses lru */struct {/* Partial pages */struct page* next;
#ifdef CONFIG_64BITint pages;/* Nr of pages left */int pobjects;/* Approximate count */
#elseshort int pages;short int pobjects;
#endif};};struct kmem_cache* slab_cache;/* not slob *//* Double-word boundary */void* freelist;/* first free object */union {void* s_mem;/* slab: first object */unsigned long counters;/* SLUB */struct {/* SLUB */unsigned inuse : 16;/* ⽤于SLUB分配器:对象的数⽬ */unsigned objects : 15;unsigned frozen : 1;};};};...};union {/* 内存管理⼦系统中映射的⻚表项计数,⽤于表⽰⻚是否已经映射,还⽤于限制逆向映射搜索*/atomic_t _mapcount;unsigned int page_type;unsigned int active;/* SLAB */int units;/* SLOB */};...
#if defined(WANT_PAGE_VIRTUAL)/* 内核虚拟地址(如果没有映射则为NULL,即⾼端内存) */void* virtual;
#endif/* WANT_PAGE_VIRTUAL */...
}
1. flags :⽤来存放⻚的状态。这些状态包括⻚是不是脏的,是不是被锁定在内存中等。flag的每⼀位单独表⽰⼀种状态,所以它⾄少可以同时表⽰出32种不同的状态。这些标志定义在<linux/page-flags.h>中。其中⼀些⽐特位⾮常重要,如PG_locked⽤于指定⻚是否锁定,PG_uptodate⽤于表⽰⻚的数据已经从块设备读取并且没有出现错误。
2. _mapcount :表⽰在⻚表中有多少项指向该⻚,也就是这⼀⻚被引⽤了多少次。当计数值为-1时,就说明当前内核并没有引⽤这⼀⻚,于是在新的分配中就可以使⽤它。
3. virtual :是⻚的虚拟地址。通常情况下,它就是⻚在虚拟内存中的地址。有些内存(即所谓的⾼端内存)并不永久地映射到内核地址空间上。在这种情况下,这个域的值为NULL,需要的时候,必须动态地映射这些页。
以4GB大小的物理内存,一个页框4kb举例。
所以我们就有4GB/4KB=1,048,576个页框也就有1,048,576个struct page;
struct page按40bity大小算,所以页框也就占40MB。对于4GB,40MB已经很小了。
如何通过页框访问到struct page
从磁盘加载到内存其实连续的,比如他要加载3个页框,那3个页框里面的东西只能是一个文件里的东西,即使第3个页框没有用完,下一个文件也会从第4个页框开始加载。4kb里的内存,都是以每个字节进行编制。所以要访问一个页框的struct page,就可以通过物理地址/4kb,就得到struct page[N]的下标了。
页表设计
再来思考一个问题
操作系统可以想为用户提供连续的地址,但是在物理地址上他并不会给我开辟连续的地址。
如果是这样我们如果保证他们要连续呢?
所以就有了我们的页表
我们页表就可以保证他们连续,在进程加载时就要对虚拟地址与物理地址进行映射?那他们时如何映射的呢?
下面以4GB大小的物理内存,一个页框4kb举例。
我们的页表并会像这样左边是虚拟地址,右边是物理地址。应为这样太占内存了!4GB的物理地址要做映射,页表最大花销就是16GB。
而有人想出了下边这个做法,非常的厉害。
以一个4bity的地址举例
我们的页目录表对一个前十个bit(一级页号)位进行解析,在去哪个页表,通过第11位到20bit位(二级页号)寻找到页表下的地址,最后的12个比特位刚好4096,最后指向每个4kb内的地址。
这里算一算页表能表示的地址有:1024*1024*4098=4294967296
再看4GB以字节序编址就有:4*1024*1024*1024=4294967296
这样不就是4GB大小的地址空间了吗。
这样的页表就只需花费1024*1024*4=4MB大小的页表就能映射4GB大小的物理内存!确实非常伟大设计!
所以我们所说页表,其实是由页表目录和页表共同组成的。上面的那种说法只是说明物理内存与虚拟内存进行映射而已