内存分配和管理
Linux 0.11内核默认最多支持16M物理内存,物理内存各部分的功能区域示意图如下所示。
对内存的管理是以页(4KB)为单位进行的,对于内核代码和数据外的内存(1M以上内存区域),使用mem_map[]数组来记录内存页面的状态,0表示空闲,100表示被占用。
系统首先计算出管理的页面数:PAGING_PAGES = (16M - 1M) / 4KB = 3840 主内存对应的页面数:(16M - 4.5M) / 4KB = 2944 ,前896项对应1M以上的高速缓存区和虚拟磁盘所占用的的物理页面,且被置为占用状态。
get_free_page
// 获取首个空闲页面,并标记为已使用,如果没有空闲页面,则返回0 unsigned long get_free_page(void) { register unsigned long __res asm("ax"); __asm__("std ; repne ; scasb\n\t" // 循环比较mem_map数组是否等于0,最大循环次数cx "jne 1f\n\t" // 没有等于0的字节,则跳转结束 "movb $1,1(%%edi)\n\t" // 1=>[1+edi],对应页面设置为1 "sall $12,%%ecx\n\t" // 页面数*4kb = 相对页面起始地址 "addl %2,%%ecx\n\t" // 加上 %2 LOW_MEM 起始地址,等于物理地址 "movl %%ecx,%%edx\n\t" // 实际物理地址->edx地址 "movl $1024,%%ecx\n\t" // ecx=1024 "leal 4092(%%edx),%%edi\n\t" // 4092 + edx->edi(页面的末端) "rep ; stosl\n\t" // edi所指内存清零 "movl %%edx,%%eax\n" // 页面起始地址->eax(返回值) "1:" :"=a" (__res) // %0 返回 :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), // 输入%1 ax=0 %2 LOW_MEM管理内存起始位置 %3 cx=PAGING_PAGES页面数 "D" (mem_map+PAGING_PAGES-1) // %4 di=mem_map尾端地址 ); return __res; }
free_page
// 释放addr处的一页内存 void free_page(unsigned long addr) { // 校验地址合法性 if (addr < LOW_MEM) return; if (addr >= HIGH_MEMORY) panic("trying to free nonexistent page"); // 获取对应页面 addr -= LOW_MEM; addr >>= 12; if (mem_map[addr]--) return; // 置0标记为空闲 mem_map[addr]=0; panic("trying to free free page"); }