linux kmalloc函数

来源:互联网 发布:242家网络小额贷款牌照 编辑:程序博客网 时间:2024/06/07 05:45
2.6内核下 kmalloc的实现中有个__you_cannot_kmalloc_that_much函数,插入这个函数的目的是作参数检查.

static inline void *kmalloc(size_t size, int flags)
{
       if (__builtin_constant_p(size)) {
              int i = 0;
             #define CACHE(x)
            if (size <= x)
                 goto found;
             else
                  i++;
             #include "kmalloc_sizes.h"
             #undef CACHE
             {
                  extern void __you_cannot_kmalloc_that_much(void);
                  __you_cannot_kmalloc_that_much();
             }
found:
             return kmem_cache_alloc((flags & GFP_DMA) ?
                 malloc_sizes[i].cs_dmacachep : malloc_sizes[i].cs_cachep, flags);
       }
       return __kmalloc(size, flags);
}

     上面的代码是2.6内核下的kmalloc函数定义,对比2.4的内核,该函数被移到了linux/slab.h头文件中作为一个static inline函数实现,所以在调用该函数时,一定要包含linux/slab.h. kmalloc是基于slab实现的,分配的内存不能超过128k, 并且实际上每次分配的内存大小都是2的幂次.


   这里只介绍一下上面代码中的那个__you_cannot_kmalloc_that_much()函数,这个函数实际上并没有定义,但是编译连接(insmod)都不会有问题,是一个很有趣的用法. 先看__builtin_constant_p(),这是gcc的内建函数,可以判断它的参数在编译时是否为常量,若是,返回值为真,否则为假,凡是通过gcc编译的c代码中都可以直接引用这一类以__builtin_打头的函数.下面的include展开的结果如下:


       if (size <= 32)
            goto found;
       else
            i++;

       if (size <= 64)
            goto found;
       else
             i++;
        ..............
       ..............
       if (size <= 131072)
            goto found;
       else
            i++;


如果size在编译时就能确定出它的大小,编译器就可以充分发挥他的优化能力,把无关代码删掉,比如size小于131072时,整个函数只剩下一个return语句了,__you_cannot_kmalloc_that_much的调用也被删掉了,所以在连接时不会有问题,否则在insmod模块的时候会告诉你该符号没有定义,这说明你给的参数size大于了128k. 这实际上是在编译连接时做了参数范围的检查,这个用法真得不多见.

kmalloc引入的目的:
内核为了提高一些常用的数据结构(一般大小远小于1个page)的内存使用效率(空间和时间上),引入slab分配器(区别于伙伴系统算法),slab分配器使用伙伴系统算法作为物理内存分的接口,但是对于slab分配器中的对象,内核释放这个对象之后,相应的物理内存并不释放,可以留给下一个可能的对象使用,这样可以提高经常使用的数据结构内存使用效率(否则导致内存碎片和让内核疲劳于不停的内存分配和释放)。对于每种常用的数据结构(比如skb_buff),内核可以使用kmem_cache_create()创建一个专用的高速缓存,但是如果对这个存储区的请求并不是那么的频繁,可以考虑使用kmalloc从通用高速缓存分配按照几何分布的存储区(从32个字节,到128k)。
vmalloc引入的目的:
系统对于物理内存的分配最终通过伙伴系统的alloc_pages实现,一般把存储区映射到一组连续的页框,但是这样无疑会引入外碎片,对于这些外碎片应该是加以合理的利用,于是引入非连续存储区的管理,非连续的存储区中非连续主要是强调物理上的非连续,但是线性地址是连续,这些线性地址是在3G+mem+8M以上地址空间中分配和管理的。
固定映射的线性地址存放在线性地址的第四个GB的末端,它是一个索引对应一个页框及其线性地址,通过索引寻找到这个线性地址,据说对于指针变量效率会更高。
其实kmalloc和vmalloc并没有太多的联系,vmalloc会调用kmalloc分配非连续线性区描述这样的对象,但他们最终都通过伙伴系统算法作为接口分配内存。


* %GFP_USER - Allocate memory on behalf of user.  May sleep. * * %GFP_KERNEL - Allocate normal kernel ram.  May sleep. * * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools. *   For example, use this inside interrupt handlers. * * %GFP_HIGHUSER - Allocate pages from high memory. * * %GFP_NOIO - Do not do any I/O at all while trying to get memory. * * %GFP_NOFS - Do not make any fs calls while trying to get memory. * * %GFP_NOWAIT - Allocation will not sleep. * * %GFP_THISNODE - Allocate node-local memory only. * * %GFP_DMA - Allocation suitable for DMA. *   Should only be used for kmalloc() caches. Otherwise, use a *   slab created with SLAB_DMA.


原创粉丝点击