本文主要介绍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),同时会释放对应的页表内存和页表项对应的物理内存。
Linux0.12内核之内存管理(2),布布扣,bubuko.com
原文地址:http://blog.csdn.net/getnextwindow/article/details/27108975