Linux内核源码分析--内存管理(二、函数实现技巧)

        仔细的分析了一下各个内存管理函数的实现,发现里面涉及到了几个技巧,如果知道了这几个技巧,那么阅读内存管理源码将会事半功倍(主要是这几个技巧在几个函数中都出现过),当然也会选择性的分析几个比较重要的函数实现;


函数实现技巧

        1、向上取整:以一个页面为了例,如果地址是1,那么向上取整就是4096;如果地址是 4095,向上取整就是4096;如果地址是4098,向上取整就是4096 x  2.......

#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
current->start_code + current->end_code)
        这个是比较addr地址是否在进程的代码段内,至于为什么要这样实现,到现在我还没弄清楚(等看完进程调度那块再到回来看看);这里用到一个技巧就是向上取整,addr是一个随机地址,要找出该地址的下一个页面的物理起始地址,那么就要向上取整了。(addr + 4095) & (~4095) :addr如果是4096的倍数,那么(addr+4095) & (~4095)结果就是addr;如果addr不是4096的倍数,那么addr以4096取余后得到的值范围为:1~4095,再加上4095得到范围:4096~4096+4094;然后&(~4095)就可以得到一个完整的4096了;其实上面的 &(~4095)就是相当于整除4096:/4096;可以使用(x + 9)/ 10,(其中x为任意数)来验证下;

        在free_page_tables()函数中:size = (size + 0x3fffff) >> 22;也是向上取整的实例;


        2、获取目录项/表项的物理起始地址:一般是从线性地址中获取到目录项/表项号,然后右移2个字节(因为一个项占用4个字节)就可以得到物理起始地址,也称目录项指针;

dir = (unsigned long *) ((from>>20) & 0xffc);
        上面函数在free_page_tables()中(其他函数中有),from是线性地址,要得到目录项号,则:from = from >> 22(线性地址中和目录项有关的只有高10,这里就是获取到高10位的地址);注意这里获取到的仅仅只是目录项的号,而不是目录项的物理地址。

        又根据一个目录项占用4个字节,那么from = from << 2(左移2位表示 乘以 2^2);所以两个合起来就干脆只右移20位得了,那么就有上面的 from >> 20了。但是这样有个问题:开始数据为1111,右移2位结果:1111 >> 2  为  0011;接着左移回2位结果:0011 << 2  为 1100,而开始的结果为1111,所以若按照这个来移动的话就会出错的。但是如果后面两位为0,则结果是正确的,相当于少移的2位是空的。

        为了解决上面的问题,干脆把低2位和谐掉,因为如果11,12位是0,那倒无所谓;但如果不是0,那么结果就出错了。0xffc == 1111 1111 1100 ,或上它就是把低2位干掉(用这种方法可以验证下 1111 移动问题)。其实本来低2位就是要舍弃的,因为目录项是4字节对齐的;

        同理,在其他函数中要获取页表项的物理地址方法类似:((address>>10) & 0xffc) 在write_verify()函数中有实现;

        

        3、修改数组映射值:这个应该不是函数设计技巧,但在内存管理中却频繁出现,而且很重要。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值