Linux源码(0.11)学习04---申请和释放内存页 get_free_page free_page

内存分配和管理

Linux 0.11内核默认最多支持16M物理内存,物理内存各部分的功能区域示意图如下所示。

Linux源码(0.11)学习04---申请和释放内存页 get_free_page free_page

 

 

 对内存的管理是以页(4KB)为单位进行的,对于内核代码和数据外的内存(1M以上内存区域),使用mem_map[]数组来记录内存页面的状态,0表示空闲,100表示被占用。

系统首先计算出管理的页面数:PAGING_PAGES = (16M - 1M) / 4KB = 3840 主内存对应的页面数:(16M - 4.5M) / 4KB = 2944 ,前896项对应1M以上的高速缓存区和虚拟磁盘所占用的的物理页面,且被置为占用状态。  

Linux源码(0.11)学习04---申请和释放内存页 get_free_page free_page

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");
}

 

Linux源码(0.11)学习04---申请和释放内存页 get_free_page free_page

上一篇:ElasticSearch Linux版安装


下一篇:C#使用redis学习笔记