《linux 内核完全剖析》 void free_page() 分析


#define PAGE_SIZE 4096

/* these are not to be changed without changing head.s etc */
#define LOW_MEM 0x100000
extern unsigned long HIGH_MEMORY;
#define PAGING_MEMORY (15*1024*1024)
#define PAGING_PAGES (PAGING_MEMORY>>12)
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
#define USED 100

extern unsigned char mem_map [ PAGING_PAGES ];

#define PAGE_DIRTY    0x40
#define PAGE_ACCESSED    0x20
#define PAGE_USER    0x04
#define PAGE_RW        0x02
#define PAGE_PRESENT    0x01



截取了一部分mm.h 的内容相当重要的说。。。。


PAGE_SIZE 定义了1页内存字节书。特别注意,高速缓冲块长度是1024 byte

LOW_MEM 机器物理内存1M

PAGING_MEMORY 15M 主内存区最多15M。。。其实这里如果内存大的话就应该会相应的变(个人推论,如有错误,欢迎指正!)

PAGING_PAGE 分页后的物理内存页面数,>>12 就是除以4M,每个页面的大小是4M,于是可以算得所有的页面数

MAP_NR(addr)得到指定内存地址映射页面号

USED 页面被占用号


mem_map 数组记录的值是每一个位,对应的页被引用的次数。 这里linux 0.12 采用了bits-map的策略


 

mem_map 数组记录的值是每一个位,对应的页被引用的次数。 这里linux 0.12 采用了bits-map的策略

关于bitmaps可以看 MOS的第三章的 Memory Management with Bitmaps (在检索目录里面有)

 http://blog.csdn.net/cinmyheart/article/details/24888847#t8



void free_page(unsigned long addr)

{

      if(addr <LOW_MEM) return; //如果addr是1M的内核模块映射页,那么是不能free掉的,free无效,主动return挂掉free_page

      if(addr>= HIGH_MEMORY)//我刚开始一直很纠结,不是很明白为什么HIGH_MEMORY会被定义成0这里》=0是干嘛。。。

          panic("tryingto free nonexistent page");

      addr-=LOW_MEM;

      addr>>=12;//右移12位,那么得到addr的页面数

      if(mem_map[addr]--)return;

/*我只能说这个后—太技巧了。如果当前mem_map[addr]== 0 那么这个页是个free page,if判断为假于是执行下面的语句,这时候实质上是试图free一个free page是错误的。如果mem_map[addr] >0 说明有进程占用这个page,那么返回,并-1 */

      mem_map[addr]=0;

      panic("tryingtofree free page");

}






一开始对HIGH_MEMORY有疑惑是因为没有找到HIGH_MEMORY被其他的数值赋值了,在mem_init里面



void mem_init(long start_mem, long end_mem)
{
    int i;

    HIGH_MEMORY = end_mem;
    for (i=0 ; i<PAGING_PAGES ; i++)
        mem_map[i] = USED;//把所有15M主内存区的mem_map 置为USED
    i = MAP_NR(start_mem);
    end_mem -= start_mem;
    end_mem >>= 12;//除以4M得到页数
    while (end_mem-->0)
        mem_map[i++]=0;//把扩展内存区的mem_map 置0,设置为空闲
}
                                    《linux 内核完全剖析》 void free_page() 分析_第1张图片




看看这两个函数,再看看其他的内存管理的函数,这函数简直就是简单到可爱啊!

调用mem_init在main.c 里面



#define EXT_MEM_K (*(unsigned short *)0x90002)

/*系统从0x90000 开始存放系统信息,0x90002存放的就是1M之后扩展的内存容量大小 extern memory 单位是KB*/

void main(void)        /* This really IS void, no error here. */
{            /* The startup routine assumes (well, ...) this */
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
     ROOT_DEV = ORIG_ROOT_DEV;
     SWAP_DEV = ORIG_SWAP_DEV;
    sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS);
    envp[1] = term;    
    envp_rc[1] = term;
     drive_info = DRIVE_INFO;
    memory_end = (1<<20) + (EXT_MEM_K<<10);

//这里把Kb为单位的EXT_MEM_K转换成byte,把内核的1M转换成byte,于是就得到了memory_end
    memory_end &= 0xfffff000;//确保边界是4M对齐的
    if (memory_end > 16*1024*1024)
        memory_end = 16*1024*1024;

//------------------------高速缓冲的结束,就是主内存区域的开始------------------------------------------

    if (memory_end > 12*1024*1024)
        buffer_memory_end = 4*1024*1024;
    else if (memory_end > 6*1024*1024)
        buffer_memory_end = 2*1024*1024;
    else
        buffer_memory_end = 1*1024*1024;
    main_memory_start = buffer_memory_end;

//-------------------------------------------------------------------------------------------------------------

#ifdef RAMDISK
    main_memory_start += rd_init(main_memory_start, RAMDISK*1024);

//这个rd_init不必在意,他返回的返回值始终就是第二个参数,不会变,可以具体的去看代码实现,我就不贴出来了
#endif
    mem_init(main_memory_start,memory_end);//这里调用mem_init初始化memory相关设置


只贴出和mem_init 有关的一段。。。



到这里。。。终于把free_page的来龙去脉摸清楚了。。。。

只有坚实的理论基础,才能深入到实践中。。。真理啊。。。要想看得懂实际的代码,还是要有理论的基础。。。。







 《linux 内核完全剖析》 void free_page() 分析_第2张图片

你可能感兴趣的:(linux,linux,kernel,System,内存管理,operating)