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

慢慢来吧~~


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;     // 扣去已经使用的page
		dir_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;
				else
					break;
			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");
		else
			task[dir_entry >> 4]->rss--;
		return 1;
	}

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

越来越复杂了



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值