Presentation is loading. Please wait.

Presentation is loading. Please wait.

第二章 LINUX存储管理 LINUX的分页管理机制.

Similar presentations


Presentation on theme: "第二章 LINUX存储管理 LINUX的分页管理机制."— Presentation transcript:

1 第二章 LINUX存储管理 LINUX的分页管理机制

2 LINUX的地址划分 每一个用户进程都可以访问4GB的线性虚拟内存空间。
从3GB到4GB的虚拟内存地址为核心态空间,存放仅供核心态访问的代码和数据,用户态进程不可访问。 所有进程从3GB到4GB的虚拟空间都是一样的,有同样的页目录项,同样的页表,对应到同样的物理内存段。LINUX以此方式让内核态进程共享代码段和数据段。 内核态虚拟空间从3GB到3GB+4M的一段(也就是进程页目录第768项所管辖的范围),被映射到物理空间0到4M段。因此,进程处于核心态时,只要通过访问虚拟空间3GB到3GB+4M段,偏移地址0到4M,即访问了物理空间0到4M段。

3 虚拟地址转换

4 mm_struct (include/linux/sched.h)
203 struct mm_struct { struct vm_area_struct * mmap; /* list of VMAs */ struct vm_area_struct * mmap_avl; /* tree of VMAs */ struct vm_area_struct * mmap_cache; /* last find_vma result */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many 进程/线程 refer to "struct mm_struct" (users count as 1) */ int map_count; /* number of VMAs */ struct semaphore mmap_sem; /* 对mmap操作的信号量 */ spinlock_t page_table_lock; struct list_head mmlist; /* List of all active mm's */ unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; unsigned long rss, total_vm, locked_vm; unsigned long def_flags; unsigned long cpu_vm_mask; unsigned long swap_cnt; /* number of pages to swap on next pass */ unsigned long swap_address; mm_context_t context; /* Architecture-specific MM context */ 227 };

5 PCB对内存的控制(之一) struct mm_struct结构的成员 pgd_t * pgd; 表示进程页目录的起始地址。

6 PCB对内存的控制

7 第二章 LINUX存储管理 虚存段(vma)的组织和管理 (克服页表中空表项过烂问题)

8 vma段 (vitual memory area)
在这段虚存里的所有单元拥有相同的特征。例如:属于同一进程,相同的访问权限,同时被锁定(locked),同时受保护(protected),等等。

9 vm_area_struct (include/linux/mm.h)
41 struct vm_area_struct { struct mm_struct * vm_mm; /* VM area parameters */ unsigned long vm_start; unsigned long vm_end; struct vm_area_struct *vm_next; /* linked list of VM areas per task, sorted by address */ pgprot_t vm_page_prot; unsigned long vm_flags; short vm_avl_height; /* AVL tree of VM areas per task, sorted by address */ struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; struct vm_area_struct *vm_next_share; struct vm_area_struct **vm_pprev_share; struct vm_operations_struct * vm_ops; unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ /* 如果vma段的内容是关于文件的,则vm_offset就是该段内容相对于文件起始位置的偏移量。 */ struct file * vm_file; unsigned long vm_raend; void * vm_private_data; /* was vm_pte, 用于共享内存,含SHM_SWP_TYPE和共享内存段id号 */ 69 };

10 vma段的链表 进程通常占用几个vma段,分别用于代码段、数据段、堆栈段等。属于同一进程的vma段通过vm_next指针连接,组成链表。如图。 struct mm_struct结构的成员struct vm_area_struct * mmap 表示进程的vma链表的表头。

11 PCB对内存的控制(之二)

12 PCB对内存的控制(之三) LINUX同时维护了一个AVL(Adelson-Velskii and Landis)树。
在树中,所有vma段均有左指针vm_avl_left指向相邻的低地址虚存段,右指针vm_avl_right指向相邻的高地址虚存段。 struct mm_struct结构的成员struct vm_area_struct * mmap_avl表示进程的AVL树的根,vm_avl_height表示AVL树的高度。 对vma段可以进行加锁、加保护等操作。

13 AVL树

14 第二章 LINUX存储管理 物理空间管理

15 物理空间的组织 (include/linux/fs.h,struct page)
物理内存以页帧(page frame)为单位,页帧的长度固定,等于页长,对INTEL CPU缺省为4K字节。 LINUX对物理内存的管理通过mem_map表描述(mm/memory.c)。 mem_map在系统初始化时由free_area_init()函数创建(mm/page_alloc.c)。 它本身是关于struct page mem_map_t (linux/mm.h)的数组,每项mem_map_t对应一个关于核心态、用户态代码和数据等的页帧。

16 mem_map在物理空间的位置

17 struct page 134 typedef struct page { 135 struct list_head list;
struct address_space *mapping; /* 见书中解释 */ unsigned long index; /* 若该页帧的内容是文件,则index指出文件的inode和偏移位置 */ struct page *next_hash; atomic_t count; /* 指明目前使用该页面的用户数。count==0意味着此页空闲 */ unsigned long flags; /* atomic flags, some possibly updated asynchronously */ struct list_head lru; unsigned long age; /* 页帧的年龄,越小越先换出 */ wait_queue_head_t wait; struct page **pprev_hash; struct buffer_head * buffers; /* 若该页帧作为缓冲区,则指示地址 */ void *virtual; /* non-NULL if kmapped */ struct zone_struct *zone; 148 } mem_map_t;

18 (Buddy System Impelmentation Codes)
第二章 LINUX存储管理 空闲物理内存管理 (Buddy System Impelmentation Codes)

19 空闲内存的组织

20 bitmap 表 在物理内存低端,紧跟mem_map表的bitmap表以位图方式记录了所有物理内存的空闲状况。
与mem_map一样,bitmap表在系统初始化时由free_area_init()函数创建(mm/page_alloc.c)。 与一般性位图不同的是,bitmap表分割成NR_MEM_LISTS组(缺省值6)。

21 bitmap 表 首先是第0组,初始化时设定了长度为(end_mem-start_mem) / PAGE_SIZE/20+3,每位表示20个页帧的空闲状况,置位表示已被占用。 接着是第1组,初始化时设定了长度为: (end_mem-start_mem) / PAGE_SIZE/21+3 ,每位表示连续21个页帧的空闲状况,置位表示其中1页或2页已被占用。 类似地,对第i组,初始化时设定了长度为: (end_mem-start_mem) / PAGE_SIZE / 2i+3 ,每位表示连续2i个页帧的空闲状况,置位表示其中1页或几页已被占用。 例如对第5组,某个bit所对应的连续32页帧中只要有一个被占用,此位即置1,只有当所有32页帧全部回收后才清0。

22 free_area数组 LINUX用free_area数组记录空闲的物理页帧。free_area数组由NR_MEM_LISTS个free_area_struct结构类型的数组元素构成,每个元素均作为一条空闲块链表的表头。 struct free_area_struct { struct page *next; /* 此结构的next,prev指针与struct page匹配 */ struct page *prev; unsigned int * map; /* 指向bitmap */ }; static struct free_area_struct free_area[NR_MEM_LISTS]; 所有单个空闲页帧组成的链表挂到free_area数组的第0项后面。连续2 i个空闲页帧则被挂到free_area数组的第i项后面。

23 操作函数 分配内存块由__get_free_pages()函数和宏定义__get_free_page()执行

24 分配算法 LINUX采用buddy算法分配空闲块,块长可以是2i个 (0<= i< NR_MEM_LISTS) 页帧。
当分配长度是2i页帧的块时,从free_area数组的第i条链表开始搜索,找不到再搜索第i+1条链表,余此类推。 若找到的空闲块长正好等于需求的块长,则直接将它从free_area删除,返回首地址。 若找到的空闲块长大于需求的块长,则将空闲块一分为二,前半部分插入free_area中前一条链表,取后半部分。 若还大,则继续对半分,留一半取一半,直至相等。 bitmap表也相应调整。每分配一个2i页帧长的块,都要将bitmap表从第i组到第NR_MEM_LISTS组的对应的bit置1。

25 释放算法 回收空闲块时,change_bit()函数根据bitmap表的对应组,判断回收块的前后邻居是否也为空。
若空则合并,即修改bitmap表中对应位,从free_area的空闲链表中取下该相邻块。 此判断是个递归过程,直至找不到空闲邻居为止。 将最后合并的最大块插入free_area的相应链表中。

26 第二章 LINUX存储管理 SLAB

27 第二章 LINUX存储管理 核心态内存的申请与释放

28 核心态内存 核心态内存是用来存放LINUX核心系统数据结构的内存区域,处于进程虚拟空间的3G至4G(精确地说应该是3G+high_memory,其中high_memory是系统在启动阶段测得的物理内存的实际容量)范围内。 核心态内存的分配和释放以块(block)为单位。

29 核心态空闲内存的组织

30 blocksize表 blocksize表规定申请内存块时可供选择的块长度:
static const unsigned int blocksize[] = { 32, 64, 128, 252, 508, 1020, 2040, 4096 – 16, 8192 – 16, – 16, – 16, – 16, – 16, 0 /* 表示blocksize表的结束 */ }; 它们近似等于2的次幂。

31 sizes表 sizes表管理那些从物理空间free_area申请得到的用于核心态内存空间分配的空闲块。
sizes表的元素类型是struct size_descriptor, 每个表项实质上就是两个由等长空闲块所组成链表的表头,一是DMA可访问的,一是一般性的。

32 char *kmalloc (unsigned long size, int priority);
核心内存的申请和释放 核心内存申请 char *kmalloc (unsigned long size, int priority); 核心内存释放 kfree(char * addr); 参见文件“kmalloc.doc”

33 kmalloc cache

34 第二章 LINUX存储管理 用户态内存的申请与释放

35 用户态内存 由vmalloc()分配的存储空间在进程的虚拟空间是连续的,但它对应的物理内存仍需经缺页中断后,由缺页中断服务程序分配。所分配的物理页帧也不是连续的。这些特征与访问用户态内存相似,所以不妨把vmalloc()和vfree()称作用户态内存的申请与释放界面。 注意,malloc()、free()与vmalloc()、vfree()不是一回事,gcc并不是利用vmalloc、vfree实现malloc、free的。

36 用户态内存的位置 可分配的虚拟空间在3G+high_memory+HOLE_8M以上高端,由vmlist链表管理。
3G是核心态赖以访问物理内存的始址,high_memory是安装在计算机中实际可用的物理内存的最高地址,因此3G+high_memory也就是(从虚拟空间中看到的)物理内存的上界。HOLE_8M则是长度为8M的“隔离带”,起到越界保护作用。 尽管vmalloc返回高于任何物理地址的高端地址,但因为vmalloc同时更改了页表甚至页目录,处理器仍能正确地访问这些高端连续地址(页目录和页表把高端虚拟地址映射到实际的物理地址)。内核态程序与进程用户态程序共享同一个页目录,同一组页表,因而内核态程序也能正常访问。

37 管理用户态内存的结构

38 操作函数 申请 void * vmalloc(unsigned long size); 释放
void vfree(void * addr); 参见文件vmalloc.doc

39 kmalloc与vmalloc的比较 vmalloc返回的地址空间不能绕过CPU的页表机构直接使用。当操作系统某些管理模块(如DMA部件)需要直接使用实际物理地址时,vmalloc不合适,必须用kmalloc。 向vmalloc申请小块内存(如1页左右)也不合适,因为无论是内存的分配还是使用,都涉及到内存和页表两方面因素。。 比较合适的情形可能是申请大块缓冲区。此时,尽管大缓冲区占用了大段虚拟地址,但实际占用的物理地址不大,因为当前不用的内容不会调入物理内存中。相反,如果用kmalloc申请大缓冲区,那么,将实实在在占用这么大的一块物理内存。何况,缺省情况下,kmalloc可分配的最大内存块只有131054字节。

40 第二章 LINUX存储管理 交换空间

41 两种交换空间 一种用整个块设备,如硬盘的一个分区,称作交换设备,效率较高; 另一种用文件系统中固定长度的文件,称作交换文件,效率较低。
LINUX允许并行管理MAX_SWAPFILES个交换空间(MAX_SWAPFILES的缺省值为8)。

42 交换空间的格式 前4096字节是一个以字符串 “SWAP_SPACE”结尾的位图。位图的每一位(bit)对应一个交换空间的页面,置位表示对应的页面可用于换页操作。 第4096字节之后则是真正存放换出页面的空间。 这样,每个交换空间最多可容纳 ( )* 8 – 1 = 32687个页面。

43 启用交换空间 int sys_swapon(const char * swapfile, int swapflags);
swapflags规定交换空间的优先数。该参数中,SWAP_FLAG_PREFER(0X8000)必须置位,SWAP_FLAG_PRIO_MASK(0X7FFF)指定一个正的优先数。如果没有指定优先数,swapon自动给出一个负的优先数,负优先数的取值决定于swapon的调用次数。

44 每注册一个交换空间,就在swap_info表中填一项swap_info_struct结构
25 struct swap_info_struct swap_info[MAX_SWAPFILES]; 49 struct swap_info_struct { unsigned int flags; /* 如果SWP_USED位置位,则被占用。如果SWP_WRITEOK,则该交换空间准备就绪。 */ kdev_t swap_device; /* 对于交换设备,swap_device属性表示交换设备的主、次设备号 */ spinlock_t sdev_lock; /* 对于此设备的互斥锁 */ struct dentry * swap_file; /* 对于交换文件,swap_file属性指向该文件的inode */ struct vfsmount *swap_vfsmnt; unsigned short * swap_map;/* 指向一张表,其每一字节按顺序对应交换空间的一个页面,字节的值代表了引用该页面的进程数 */ unsigned int lowest_bit; /*交换空间中的第一个没有被任何进程使用的交换页在swap_map数组中的下标 */ unsigned int highest_bit; /* 交换空间中最后一个没被任何进程使用的交换页的下标 */ unsigned int cluster_next; /*上次从当前的cluster中成功分配的交换页面的后继页面在swap_map数组中的下标 */ unsigned int cluster_nr; /* 当前cluster中可供使用的交换页面的个数 */ int prio; /*交换空间的优先级。优先级越高,交换文件申请交换页面的时候越优先考虑 */ int pages; /* 表示该交换空间尚有多少空闲空间可供保存进程换出的物理页 */ unsigned long max; int next; /*指向下一项交换空间的的指针 */ 64 }; 153 struct swap_list_t { int head; /* head of priority-ordered swapfile list */ int next; /* swapfile to be used next */ 156 }; 23 struct swap_list_t swap_list = {-1, -1};

45 int sys_swapoff(const char * swapfile);
注销交换空间 int sys_swapoff(const char * swapfile);

46 交换空间的工作 kswapd进程换出页面时,调用try_to_swap_out() 测试页面的年龄。如果某物理页面可以换出,则调用get_swap_page向swap_list.next指示的交换空间申请空闲页面,得到一地址entry。该地址写入进程页表中那个原来描述换出物理页面的页表项,替换了其中的页帧地址。最后,调用rw_swap_page(),将换出的物理页面写到entry指定的交换空间某个页面中。 反过来,当缺页中断发生时,缺页中断服务程序可以根据产生缺页的地址(由CR2寄存器给出),找到描述该页面的页表项。页表项的Present位应该为0,最高20位指出该页面保存在哪个交换空间的哪个页面中。然后,经一系列函数调用后,读入该页面。

47 第二章 LINUX存储管理 页交换进程和页面换出

48 kswapd 当物理页面不够时,利用kswapd释放部分物理页面,将它们的内容写到交换空间。
kswapd是一特殊的进程,称内核态线程(kernel thread)。 注意,kernel thread完全不同于通常意义上的线程。它是没有虚拟存储空间的进程,它只运行在内核态,直接使用物理地址空间。同类型的进程还有bdflush和init。 kswapd的作用超越了字面上的描述。它不仅能将页面换出到交换空间(交换区或交换文件),它也保证系统中有足够的空闲页面以保持存储系统高效地运行。

49 由于只有该映像区的开始部分调入内存,因此,进程迟早会执行到那些尚未调入内存的代码。
第二章 LINUX存储管理 缺页中断和页面换入 由于只有该映像区的开始部分调入内存,因此,进程迟早会执行到那些尚未调入内存的代码。

50 产生缺页中断 当一个进程访问了一个还没有有效页表项的虚拟地址时(即页表项的P位为0),处理器将产生缺页中断,通知操作系统,并将出现缺页的虚存地址(在CR2寄存器中)和缺页时访问虚存的模式一并传递给LINUX的缺页中断服务程序。

51 缺页中断服务程序为do_page_fault()
set_trap_gate(14, &page_fault); /* arch/i386/kernel/trap.c */ ENTRY(page_fault) /* arch/i386/kernel/entry.S */ pushl $SYMBOL_NAME(do_page_fault) jmp error_code /* 异常中断服务程序的统一入口 */

52 中断服务流程 根据控制寄存器CR2传递的缺页地址,找到用来表示出现缺页的虚拟存储区的vm_area_struct结构。
如果没有找到与缺页相对应的vm_area_struct结构,那么说明进程访问了一个非法存储区,LINUX向进程发送信号SIGSEGV。 接着检测缺页时访问模式是否合法。如果进程对该页的访问超越权限,例如试图对只允许读操作的页面进行写操作,系统也将向该进程发送一个信号,通知进程的存储访问出错。 主要流程参见文件pagefault.doc


Download ppt "第二章 LINUX存储管理 LINUX的分页管理机制."

Similar presentations


Ads by Google