1.kmalloc
改函数包含于linux/slab.h中
函数模型为: void *kmalloc(size_t size, int flags)
执行该函数,不对所获取的内存空间清零。不过分配的区域中物理内存中是连续的。对于32位的机器而言,改函数返回的地址应该在c0000000 ~ e0000000之间。即从虚拟地址3GB开始一直到最后的128MB之间。
flags比较常用的是GFP_KERNEL(代表运行在内核空间的进程执行),GFP_USER(为用户分配),GFP_ATOMIC(用于在中断处理例程或者其他运行于进程上下文之外的代码中分配内存,例如tasklet,定时器等)
根据头文件可以发现,kmallloc分配是基于slab分配器的。可以说kmalloc使用slab为普通对象分配块。
对应的释放函数为kfree
2.vmalloc
改函数包含于linux/vmalloc.h中
改函数分配的空间是内核后128MB中的空间。所以返回的地址应该大于e0000000。我在驱动中用vmalloc一次分配了两页,地址分别为f7edf000与f7ee2000。
尽管它分配虚拟地址空间的连续区域,但是物理上可能是不连续,因此,为了得到连续的虚拟地址,就需要修改页表。因此这将带来比较大的开销,甚至污染页表。带来低效。
ldd3上说,vmalloc分配得到的地址是不能在微处理器之外使用的。
另外,需要注意的是,vmalloc不能在原子上下文中使用,因为它调用了kmalloc(GFP_KERNEL),因此可能休眠。
在linux中的一个应用是create_module系统调用
对应的释放函数为vfree.
3.后备高速缓存
这也是slab的一个应用。如果说kmalloc是对通用对象的分配。那么后备告诉缓存的使用是争对专用对象的。
首先利用kmem_cache_create(const char *name, size_t size, size_t offset, unsigned long flag, void *constructor, void
后两个参数为构造函数与析构函数,可以直接使用NULL。name是要分配的数据结构的名字。offset用于特殊对齐,一般为0. 而size就是专用数据对象的大小。
以后每次调用kmem_cache_alloc,就会自动分配size大小的对象。
对应释放的函数为kmem_cache_free,
当将所有alloc的数据对象都free之后就可以使用kmem_cache_destroy来释放高速缓存区。
4.内存池
这种方式是以后备高速缓冲作为基础的。只是作为提前做一个储备的过程。
首先使用后备高速缓存.
cache = kmem_cache_create(...)
然后使用 pool = mempool_create(MININUM, mempool_alloc_slab, mempool_free_slab, cache)建立内存池,其实际上只是多次调用分配函数为预先分配的对象创建内存池。MININUM指定了reserve的个数。
以后调用Mempool_alloc的时候,首先通过分配函数获得对象,分配失败,则返回预先分配的对象。
mempool_free的使用正好相反,首先返回预先,直到MININUM满足了,就释放到系统中。
应该记得:mempool会分配一些内存块,空闲但是不会真正的使用。
5.get_free_page
面向页的分配技术。基于页的分配策略的优点在于有效地使用了内存。通过__get_free_page获得的页面是完全属于我们自己的,可以通过调整页表合并成一个线性区间。(利用mmap函数)
对应的释放函数为free_page
以上的5中方式返回的都是虚拟地址。是可以直接可以作为指针使用的
6.alloc_pages
内核中为我们提供了两个宏定义
struct page
struct page
page数据结构是描述单个内存页的数据结构。尤其在需要高端内存的地方会经常使用
高端内存中32位机器上有可能没有相对应的线性地址,而页描述符的线性地址总是存在的。
对应的释放函数为__free_page(struct page *page)与__free_pages
通过proc中的slabinfo可以看到kmalloc使用的slab都是很规则的大小,比如小的如kmalloc-8, kmalloc-16 而大的kmalloc-2048。由此可以看到,使用kmalloc完全可以分配8字节的数据对象。这个ldd3上讲的就有点小的出入。这也是跟特定系统有关。
还可以通过cat /proc/buddyinfo看到不同zone的信息,也就是DMA,Normal,HighMem中的各种系数。