首页 > 代码库 > Linux0.12内核之内存管理(2)

Linux0.12内核之内存管理(2)

本文主要介绍Linux0.12内核memory.c中的函数

1.void free_page(unsigned long addr)
//释放物理地址addr处的一页内存。用于free_page_tables()函数
void free_page(unsigned long addr)
{
//首先判定给定物理地址的合理性。如果物理地址addr小于内存低端1M,对此不///予处理。如果addr>=内存最高端,则显示出错并且内核停止工作
if(addr<LOW_MEM) return;
if(addr>=HIGH_MEMORY)
panic("trying to free nonexistent page");
//如果对参数验证通过,那么就根据这个物理地址换算出从内存低端开始计算的//内存页面号。页面号=(addr-LOW_MEM)/4096。可见页面号从0号开始计起。此///时addr中存放着页面号。如果该页面号对应的页面映射字节不等于0,则减1返//回。此时映射字节值应该是0,表示页面已经释放。如果对应页面字节原本就///是0,表示该物理页面本来就是空闲的,说明内核代码出问题,于是显示出错///并停机。
addr-=LOW_MEM;
addr>>=12;
if(mem_map[addr]--) return;
mem_map[addr]=0;
panic("trying to free page);
}
2.int free_page_tables(unsigned long from,unsigned long size)
//该函数释放页表连续的内存块,只处理4MB长度的内存块
//根据指定的线性地址和限长(页表个数),释放对应内存页表指定的内存块并置表项//空闲。页目录位于物理地址0开始处,共1024项,每项4字节,共占4KB。每个目录//项指定一个页表。内核页表从物理地址0x1000处开始,共4个页表。每个页表有10//24项,每项4B,因此也占4KB内存。每个页表最多可以映射1KB*4B=4M的物理内存。
//参数:from--起始线性地址;size--释放的字节长度
int free_page_tables(unsigned long from,unsigned long size)
{
unsigned long *pa_table;
unsigned long *dir,nr;

//首先检测参数from是否在4MB的边界上,因为该函数只能处理这种情况。若fr//om=0,则出错,说明释放内核和缓冲所占空间
if(from & 0x3fffff)
panic("free_page_tables called with wrong alignment")
if(!from)
panic("Trying to free up swapper memory space");

//然后计算参数size给出的长度所占的页目录项目数(4MB的进位整数倍),也即所占页表数。因为一个页表可管理4MB物理内存,所以这里用右移22位的方式把需要复制的内存长度值除以4MB。其中加上0x3fffff(即4MB-1)用于得到进位整数倍结果。即除操作若有余数则进1。例如原size=4.01MB,那么可到结果size=2。接着计算给出的线性地址对应的起始目录项。对应的目录项号=from>>22。因为每项占4字节,并且由于页目录表从物理地址0开始存放,因此实际目录项指针=目录项号<<2,也即from>>20。

size=(size+0x3fffff)>>22;
dir=(unsigned long *)((from>>20) & 0xffc);

//此时size是释放的页表个数,即页目录项数,而dir是起始目录项指针。现在开始循环操作页目录项,依次释放每个页表中的页表项(??具体什么操作叫释放)。如果当前目录项无效(p=0),表示该目录项没有使用(对应的页表不存在),则继续处理下一个目录项。否则从目录项中取出页表地址pg_table,并对该页表中1024个表项进程处理,释放有效页表项对应的物理内存页面,或者从交换设备中释放无效页表项对应的页面,即释放交换设备中对应的内存页面。

for(;size-->0;dir++)
{
if(!(1 & *dir))
continue;
pg_table=(unsigned long *)(0xfffff000 & *dir);
for(nr=0;nr<1024;nr++)
{
if(*pg_table)
{
if(1 & *pg_table)
{
free_page(0xfffff000 & *pg_table)
}
else
swap_free(*pg_table>>1);
*pg_table=0;
}
pg_table++;
}
free_page(0xfffff000 & *dir);
*dir=0;//对应页表的页目录项清零
}
invalidate();
return 0;
}


总结:

1.free_page()用于释放指定物理地址处的一页物理内存。假如物理地址对应的页号是addr,那么何谓释放?物理内存就在那里,我们所谓的获取物理内存,其实就是使用一个标志,说明我们占用了他,相对应的,所谓的释放就是清除表示,说明我们我们释放了内存,释放的本质就是:mem_map[addr]--。

2.free_page_tables()以一个页表对应的物理内存为单位,释放指定线性地址和长度(页表个数)对应的物理内存页块。不仅对管理线性地址的页目录项和页表中的页表项内容进行修改(修改其实就是清0),同时会释放对应的页表内存和页表项对应的物理内存。