xv6源码解析(三)——内存管理

01 内存管理

内存管理:通过编写物理页分配器,以链表管理所有空闲页帧, 实现了对物理页帧的回收与分配;在xv6系统sbrk内存管理方式的基础上,添加了进程用户空间非连续分区的分配。

xv6源码解析(三)——内存管理_第1张图片

xv6源码解析(三)——内存管理_第2张图片

内存管理参考链接

mmap

02 sbrk机制

描述:
brk()和sbrk()改变程序间断点的位置。程序间断点就是程序数据段的结尾。(程序间断点是为初始化数据段的起始位置).通过增加程序间断点进程可以更有效的申请内存 。当addr参数合理、系统有足够的内存并且不超过最大值时brk()函数将数据段结尾设置为addr,即间断点设置为addr。sbrk()将程序数据空间增加increment字节。当increment为0时则返回程序间断点的当前位置。

返回值:
brk()成功返回0,失败返回-1并且设置errno值为ENOMEM(注:在mmap中会提到)。
sbrk()成功返回之前的程序间断点地址。如果间断点值增加,那么这个指针(指的是返回的之前的间断点地址)是指向分配的新的内存的首地址。如果出错失败,就返回一个指针并设置errno全局变量的值为ENOMEM。

总结:
这两个函数都用来改变 “program break” (程序间断点)的位置,改变数据段长度(Change data segment size),实现虚拟内存到物理内存的映射。
brk()函数直接修改有效访问范围的末尾地址实现分配与回收。sbrk()参数函数中:当increment为正值时,间断点位置向后移动increment字节。同时返回移动之前的位置,相当于分配内存。当increment为负值时,位置向前移动increment字节,相当与于释放内存,其返回值没有实际意义。当increment为0时,不移动位置只返回当前位置。参数increment的符号决定了是分配还是回收内存。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nUPoIDFQ-1668171558979)(https://image-1312312327.cos.ap-shanghai.myqcloud.com/20170116174212008)]

03 myalloc/myfree机制

xv6内存管理方法:sbrk机制

在学习完xv6的进程分配和释放内存的方式后,发现xv6只允许扩展和收缩进程空间,也就是采用了linux中提供的sbrk机制。

  • sys_sbrk()将进一步调用growproc(n)进行内存空间的调整 , proc.c中的growproc(n)底层实现原理就是根据传入参数n的正负进行扩展和收缩内存
  • kalloc()会分配一个物理页帧,kfree()会释放一个物理页帧,mappages()用于建立虚存地址和物理页帧之间的关系
  • 如何实现Linux的alloc()和free()

myalloc实现

进行myalloc分配内存的时候

(1)需要查找合适的地址范围,并创建vma进行描述

在sbrk调用的基础上,找到size,然后myalloc传入的参数n就是要分配内存空间的大小,继续往上的vm空间查找合适的地址范围

(2)要用kalloc分配足够的物理页帧,并用mappages()将这些页帧映射到指定的虚存地址上

找到对应的地址范围后,分配物理页帧,同时进行页表映射,把物理页帧映射到虚存地址上去

int 
mygrowproc(int n){                 // 实现首次最佳适应算法
	struct vma *vm = proc->vm;     // 遍历寻找合适的空间
	int start = proc->sz;          // 寻找合适的分配起点
	int index;
	int prev = 0;
	int i;

	for(index = vm[0].next; index != 0; index = vm[index].next){
		if(start + n < vm[index].address)
			break;
		start = vm[index].address + vm[index].length;
		prev = index;
	}
	
	for(i = 1; i < 10; i++) {            // 寻找一块没有用的 vma 记录新的内存块
		if(vm[i].next == -1){
			vm[i].next = index;			
			vm[i].address = start;
			vm[i].length = n;

			vm[prev].next = i;
			
			myallocuvm(proc->pgdir, start, start + n);
			switchuvm(proc);
			return start;   // 返回分配的地址
		}
	}
	switchuvm(proc);
	return 0;
}

int 
myallocuvm(pde_t *pgdir, uint start, uint end) {
	char* mem;
	uint a;

	a = PGROUNDUP(start);
	for(; a < end; a += PGSIZE) {
		mem = kalloc();
		memset(mem, 0, PGSIZE);
    mappages(pgdir, (char*)a, PGSIZE, V2P(mem), PTE_W|PTE_U);
	}
	return (end-start);
}

myfree实现

进行myfree释放内存的时候

(1)需要释放所涉及的页帧,逐个解除页表映射

(2)删除vma

int
myreduceproc(int address){  // 释放 address 开头的内存块
	int prev = 0;
	int index;
	for(index = proc->vm[0].next; index != 0; index = proc->vm[index].next) {
		if(proc->vm[index].address == address && proc->vm[index].length > 0) {
			mydeallocuvm(proc->pgdir, proc->vm[index].address, proc->vm[index].address + proc->vm[index].length);			
			proc->vm[prev].next = proc->vm[index].next;
			proc->vm[index].next = -1;
			proc->vm[index].length = 0;
			break;
		}
		prev = index;
	}
	switchuvm(proc);
	return 0;
}

int
mydeallocuvm(pde_t *pgdir, uint start, uint end) {
	pte_t *pte;
	uint a, pa;

	a = PGROUNDUP(start);
	for(; a < end; a += PGSIZE) {
		pte = walkpgdir(pgdir, (char*)a, 0);
		if(!pte)
			a += (NPTENTRIES - 1) * PGSIZE;
		else if((*pte & PTE_P) != 0){
			pa = PTE_ADDR(*pte);
			if(pa == 0)
				panic("kfree");
			char *v = P2V(pa);
			kfree(v);
			*pte = 0;
		}
	}
	return 1;
}

myalloc测试代码

myalloc => myalloc、myfree => mygrowproc、myreduceproc => myallocuvm、mydeallocuvm

#include "types.h"
#include "stat.h"
#include "user.h"


int
main(int argc, char *argv[]) {
  // int pid = getpid();   
  // map(pid);
  
  char* m1 = (char*)myalloc(2 * 4096);
  char* m2 = (char*)myalloc(3 * 4096);
  char* m3 = (char*)myalloc(1 * 4096);
  char* m4 = (char*)myalloc(7 * 4096);
  char* m5 = (char*)myalloc(9 * 4096);

  m1[0] = 'h';
  m1[1] = '\0';


  printf(1,"m1:%s\n",m1);
  myfree(m2);

  //m2[1] = 'p';

  myfree(m4);
  
  // map(pid);
  sleep(5000);
  myfree(m1);
  myfree(m3);
  myfree(m5);
  // char *p=(char *)0x0000;
  // for(int i=0x0000;i<0x08;i++)
  //     *(p+i)='*';

  // printf(1,"This string shouldn't be modified!\n");
  // exit();


  exit();
}

你可能感兴趣的:(#,嵌入式系统开发,算法,linux)