[LDD3速记]_内存分配

一、kmalloc函数

原型:

#include <linux/slab.h>
void *kmalloc(size_t size, int flags);

最终总是调用get_free_pages(GFP)实现


1. flags参数

        常用的标志:

        GFP_KERNEL:运行于进程上下文,可休眠以等待一个页面(休眠时内核把缓冲区的内容刷写到硬盘,或者从一用户进程换出内存,以获取一个内存页面)

        GFP_ATOMIC:原子性分配,可在进程上下文之外被调用(如中断处理进程、tasklet以及内核定时器)

        还有一些标志控制如何进行分配,可以上面的“或”起来使用:

        __GFP_DMA:分配DMA区段的内存

        __GFP_HIGHMEM:可位于高端内存(但是kmalloc不能分配高端内存)

        Linux内核把内存分为三个区段:DMA内存、常规内存、高端内存


2. size参数

        内核只能分配一些预定义的、固定大小的字节数组

        kmalloc能处理的最小的内存块是32或64,最大不该超过128KB(为了具有完整的移植性)


二、后备高速缓存

        驱动程序经常反复分配同一大小的内存块,为这些块增加某些特殊的内存池,这种形式的内存池称为后备高速缓存(lookasidecache)

        内核的高速缓存管理器有时称为“slab分配器”,它实现的高速缓存具有kmem_cache_t类型,通过kmem_cache_create创建

kmem_cache_t *kmem_cache_create(const char *name, size_t size,
                                size_t offset,
                                unsigned long flags,
                                void (*constructor)(void *, kmem_cache_t *,
                                                    unsigned long flags),
                                void (*destructor)(void *, kmem_cache_t *,
                                                   unsigned long flags));

        该函数创建一个高速缓存对象,可容纳任意数目的内存区域,由size决定,name保管一些信息以便追踪(可直接用字符串),offset为第一个对象的偏移量

        flags标志:

        SLAB_NO_REAP:保护高速缓存不被减少(系统寻找内存时)

        SLAB_HWCACHE_ALIGN:要求所有数据对象跟高速缓存行(cache line)对齐

        SLAB_CACHE_DMA:从DMA内存区段分配

        constructor、destructor:可选参数(不能只有destructor而没有constructor),前者用于初始化新分配的对象,后者用于释放对象

void *kmem_cache_alloc(kmem_cache_t *cache, int flags);
/* 创建高速缓存对象后,可调用此函数从中分配内存对象,其中flags与kmalloc的相同 */

void kmem_cache_free(kmem_cache_t *cache, const void *obj);
/* 释放内存对象 */

int kmem_cache_destroy(kmem_cache_t *cache);
/* 释放高速缓存对象,需内存对象均归还才能成功,若失败->内存泄漏 */

        可从/proc/slabinfo获得高速缓存的使用情况


三、get_free_page

        分配大块内存,面向页,不产生内存碎片

get_zeroed_page(unsigned int flags);
/* 返回新页面的指针,并清零 */

__get_free_page(unsigned int flags);
/* 返回新页面的指针,不清零 */

__get_free_pages(unsigned int flags, unsigned int order);
/* 分配若干页(物理连续),返回第一个字节的指针,不清零 */

        其中flags与kmalloc的一样,order是页面数的以2为底的对数(log 2 N),可以使用函数get_order()转换

void free_page(unsigned long addr);
void free_pages(unsigned long addr, unsigned long order);
/* 释放页面,第一个函数是一个宏,调用第二个函数 */

        alloc_pages接口:

struct page *alloc_pages_node(int nid, unsigned int flags,unsigned int order);
/* Linux页分配器核心代码 */

struct page *alloc_pages(unsigned int flags, unsigned int order);
struct page *alloc_page(unsigned int flags);
/* 两个宏 */

void __free_page(struct page *page);
void __free_pages(struct page *page, unsigned int order);
void free_hot_page(struct page *page);//高速缓存中的
void free_cold_page(struct page *page);//高速缓存中的
/* 释放 */

四、vmalloc函数

1 .特性

        虚拟地址连续,但物理地址可能不连续

        分配的内存使用起来效率不高,不鼓励使用

        与kmalloc的差异:kmalloc返回的虚拟地址与物理内存是一一对应的(可能有PAGE_OFFSET偏移),而vmalloc的虚拟地址需建立页表进行映射,故当需要真正的物理地址时不应使用vmalloc

        不能用于原子上下文,内部调用kmalloc(GFP_KERNEL),可能休眠


2. 接口

#include <linux/vmalloc.h>

void *vmalloc(unsigned long size);//分配
void vfree(void * addr);//释放
/* 使用示例:create_module */

void *ioremap(unsigned long offset, unsigned long size);
void iounmap(void * addr);//释放
/* 
与vmalloc一样会建立页表,但不实际分配内存
更多用于映射(物理的)PCI缓冲区地址到(虚拟的)内核空间
返回的地址需用readb或其他I/O函数来访问,不应直接访问
*/

五、获取大的、连续的缓冲区

        方法:在引导时获得专用缓冲区

#include <linux/bootmem.h>

void *alloc_bootmem(unsigned long size);
void *alloc_bootmem_low(unsigned long size);
void *alloc_bootmem_pages(unsigned long size);
void *alloc_bootmem_low_pages(unsigned long size);
/* _low版本防止分配高端内存(高端内存不能用于DMA操作) */

void free_bootmem(unsigned long addr, unsigned long size);
/* 注意:释放的部分页面不会返回给系统 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值