Linux 虚拟内存发展历史 个人笔记

来源:互联网 发布:工业管道绘图软件 编辑:程序博客网 时间:2024/05/16 09:45

慢慢来吧~~


Linux 系统自 V0.12 就加入了对虚拟内存的支持.


我们先看下Linux V0.11 对内存管理的支持情况:


Linux V0.11 对内存是以页(1024K) 为单位管理的.  所有的页的使用情况存储在数组pg_dir 中.

提供free_page , get_free_page 之类的接口来释放或者获取页面.

提供put_page 接口来将页面映射到具体地址.


Linux V0.12

虚拟内存实现细节.

1. 在get_free_page中 , 当发现没有空闲内存页面的时候, 就尝试调用换出接口 swap_out .

unsigned long get_free_page(void){register unsigned long __res asm("ax");repeat:__asm__("std ; repne ; scasb\n\t""jne 1f\n\t""movb $1,1(%%edi)\n\t""sall $12,%%ecx\n\t""addl %2,%%ecx\n\t""movl %%ecx,%%edx\n\t""movl $1024,%%ecx\n\t""leal 4092(%%edx),%%edi\n\t""rep ; stosl\n\t""movl %%edx,%%eax\n""1:":"=a" (__res):"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),"D" (mem_map+PAGING_PAGES-1):"di","cx","dx");if (__res >= HIGH_MEMORY)goto repeat;if (!__res && swap_out())goto repeat;return __res;}


swap_out 接口遍历内存数组, 查找当前可用的内存并尝试换出, 若内存已写,则保存到磁盘

中,否则直接释放.

换入磁盘的页面,其内存页表项将会改写为对应的磁盘页掩码X2 . 这样将来就可以对应的

换入.

int try_to_swap_out(unsigned long * table_ptr){unsigned long page;unsigned long swap_nr;page = *table_ptr;if (!(PAGE_PRESENT & page))return 0;if (page - LOW_MEM > PAGING_MEMORY)return 0;if (PAGE_DIRTY & page) {page &= 0xfffff000;if (mem_map[MAP_NR(page)] != 1)   // 内存在使用中return 0;if (!(swap_nr = get_swap_page())) // 获得一个空闲的磁盘页return 0;*table_ptr = swap_nr<<1;          // 页表项改为记录磁盘页吗invalidate();            write_swap_page(swap_nr, (char *) page);free_page(page);                   return 1;}*table_ptr = 0;invalidate();free_page(page);return 1;}/* * Ok, this has a rather intricate logic - the idea is to make good * and fast machine code. If we didn't worry about that, things would * be easier. */int swap_out(void){static int dir_entry = FIRST_VM_PAGE>>10;static int page_entry = -1;int counter = VM_PAGES;int pg_table;while (counter>0) {pg_table = pg_dir[dir_entry];if (pg_table & 1)break;counter -= 1024;     // 扣去已经使用的pagedir_entry++;if (dir_entry >= 1024)dir_entry = FIRST_VM_PAGE>>10;}pg_table &= 0xfffff000; //找到一个有效页表项while (counter-- > 0) {page_entry++;if (page_entry >= 1024) {page_entry = 0;repeat:dir_entry++;if (dir_entry >= 1024)dir_entry = FIRST_VM_PAGE>>10;pg_table = pg_dir[dir_entry];if (!(pg_table&1))     // 页面无效 , 可能已经在swap中if ((counter -= 1024) > 0)       // BUG goto repeat;elsebreak;pg_table &= 0xfffff000; // 页面有效  }if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) // 置换一页.return 1;}printk("Out of swap-memory\n\r");return 0;}

Linux V0.95

1. 修改try_to_swap_out的一个BUG

page &= 0xfffff000;

2. 修改swap_out的BUG

int swap_out(void){static int dir_entry = 1024;static int page_entry = -1;int counter = VM_PAGES;int pg_table = 0;repeat:while (counter > 0) {counter -= 1024;dir_entry++;if (dir_entry >= 1024)dir_entry = FIRST_VM_PAGE>>10;if (pg_table = pg_dir[dir_entry])break;}if (counter <= 0) {printk("Out of swap-memory\n");return 0;}if (!(pg_table & 1)) {printk("bad page-table at pg_dir[%d]: %08x\n\r",dir_entry,pg_table);return 0;}pg_table &= 0xfffff000;while (counter > 0) {counter--;page_entry++;if (page_entry >= 1024) {page_entry = -1;goto repeat;}if (try_to_swap_out(page_entry + (unsigned long *) pg_table))return 1;}printk("Out of swap-memory\n\r");return 0;}

Linux V0.95a

全面改写了 swap_out 接口 , 仍然是随便找一个换出去.

int swap_out(void){static int dir_entry = 1024;static int page_entry = -1;int counter = VM_PAGES;int pg_table;check_dir:if (counter < 0)goto no_swap;if (dir_entry >= 1024)dir_entry = FIRST_VM_PAGE>>10;if (!(1 & (pg_table = pg_dir[dir_entry]))) {              // 找个可用的一级页表if (pg_table) {printk("bad page-table at pg_dir[%d]: %08x\n\r",dir_entry,pg_table);pg_dir[dir_entry] = 0;}counter -= 1024;dir_entry++;goto check_dir;}pg_table &= 0xfffff000;check_table:if (counter < 0)goto no_swap;counter--;page_entry++;if (page_entry >= 1024) {page_entry = -1;dir_entry++;goto check_dir;}if (try_to_swap_out(page_entry + (unsigned long *) pg_table))      // 一一尝试换出return 1;goto check_table;no_swap:printk("Out of swap-memory\n\r");return 0;}

Linux V0.95c

swap_out加入对进程的一点操作\

if (try_to_swap_out(page_entry + (unsigned long *) pg_table))             rerurn 1;
==>

if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {if (! task[dir_entry >> 4])printk("swapping out page from non-existent task\n\r");elsetask[dir_entry >> 4]->rss--;return 1;}

之后的版本不再默认一级页表总是在地址0

越来越复杂了



0 0
原创粉丝点击