可以看到,数组项数是除去最低1M内存后可以分成的页面数,也就是可以用的物理内存页面。系统在初始化的时候把还没有被使用的内存物理页面对应的项置为了0,初始代码如下:
399 void mem_init(long start_mem, long end_mem)
400 {
401 int i;
402
403 HIGH_MEMORY = end_mem;
404 for (i=0 ; i405 mem_map[i] = USED;
406 i = MAP_NR(start_mem);
407 end_mem -= start_mem;
408 end_mem >>= 12;
409 while (end_mem-->0)
410 mem_map[i++]=0;
411 }
其实前面所有的申请内存的程序里都最终使用了一个函数get_free_page(),不管申请多少的内存,最终还是要按页面来申请:
63 unsigned long get_free_page(void)
64 {
65 register unsigned long __res asm("ax");
66
67 __asm__("std ; repne ; scasb\n\t"
68 "jne 1f\n\t"
69 "movb ,1(%%edi)\n\t"
70 "sall ,%%ecx\n\t"
71 "addl %2,%%ecx\n\t"
72 "movl %%ecx,%%edx\n\t"
73 "movl 24,%%ecx\n\t"
74 "leal 4092(%%edx),%%edi\n\t"
75 "rep ; stosl\n\t"
76 "movl %%edx,%%eax\n"
77 "1:"
78 :"=a" (__res)
79 :"" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
80 "D" (mem_map+PAGING_PAGES-1)
81 :"di","cx","dx");
82 return __res;
83 }
这个函数就是在物理内存中找一张没有使用的页面并返回其物理地址。这是一段gcc内联汇编,它在mem_map数组中的最后一项一直向前找,只要找一项的值不为0,则用这个数组下标计算出物理地址返回,并把那一项的值设为1。用下标计算物理地址的方法我想是这样的:index*4096+LOW_MEN (std;repne;scasb,这三句是依次检查mem_map里的每一项的值,如果全部不为0,也即没有物理内存可以用,立即返回0。movb ,1(%%edi)这句就是把mem_map数组里找到的可用的一项的标志设为1。此时ecx里的值就是数组下标,因此sall ,%%ecx就是index*4096,addl %2,%%ecx即把刚才的index*4096+LOW_MEM。73,74,5三句是把相应的物理内存空间内容全部清0。movl %%edx,%%eax显然是返回值了)。
![]() |

