Linux内核 内存分配(上)
分配内存
一.kmalloc函数和vmalloc函数
1.kmalloc
Driver中常用的内存分配函数,void *kmalloc(size_t size, gfp_t flags)
参数:分配到的内存空间在物理上是连续的, size是想要分配的内存空间大小, flags是分配掩码. 常用掩码为GFP_ATOMIC和GFP_KERNEL.
成功:返回低端物理内存页面所对应的线性内核虚拟地址
失败:返回NULL(因内存不足导致分配失败)
其他:用kmalloc分配的内存, 释放用kfree函数 / kzalloc: 用0来填充分配出来的内存空间.
2.vmalloc
void *vmalloc(unsigned long size).
特点: 在vmalloc区分配一段连续的虚拟地址空间, 其所映射的物理地址可能不连续, 通过伙伴系统获取内存页时,
使用了GFP_KERNEL | _GFP_HIGHMEM标志, 不能保证原子性, 且在ZONE_HIGHMEM分配物理页面.
释放: void vfree(const void *addr)
3.kmalloc和vmalloc的联系和区别
kmalloc可以通过GFP_ATOMIC达到分配内存的原子性; vmalloc不能保证原子性,不能在中断上下文中使用. vmalloc涉及对页表项的操作, vmalloc区虚拟地址与高端内存的映射, 所以效率不如kmolloc, linux driver中优先考虑kmalloc.
需要分配一段大内存, 系统中能满足要求的连续物理页面不一定存在, 用vmalloc分配一段连续的虚拟地址空间, 然后映射到分 散的物理页面来满足要求
4.内存区段
Linux内核把内存分为三个区段:
可用于DMA的内存:通常的内存分配都是发生在常规内存区
常规内存:存在于特别地址范围内的内存,外设可以利用这些内存执行DMA访问
高端内存:32位平台为了访问相对大量的内存而存在的一种机制
二.后备高速缓存
反复使用的块变成某些特殊的内存池,内核中确实有,被称为后备高速缓存。
1.指定mempool对象,即创建内存池:mempool_create 2.分配对象函数:mempool_alloc 3.释放对象函数:mempool_free 4.调整mempool大小:mempool_resize 5.销毁内存池:mempool_destroy
三.get_free_pages和相关函数
如果模块需要分配大块的内存,使用面向页的分配技术会更好一些。 分配页面:get_zeroed_page: 返回指向新页面的指针并将页面清零 释放页面:free_page(s): 不加s的是一个宏,是对加s的函数的调用
四.per-CPU
1.定义
建立一个per-CPU变量时, 系统中的每个CPU都会拥有该变量的特有副本. 每个处理器访问自己的副本无需加锁, 可以放入自己的cache中,极大地提高了访问与更新效率.常用于计数器.
2. API:
DEFINE_PER_CPU(type, name) //定义per-CPU变量
DECLARE_PER_CPU(type, name) //声明per-CPU变量
3.访问静态声明的per-CPU变量:
get_cpu_var(variable)
put_cpu_var(variable)
由于CPU在访问并修改某个per-CPU变量的临界区时, 应避免内核抢占,
所以调用get_cpu_var宏, 该宏会使用preempt_disable()禁止抢占, 访问结束后调用put_cpu_var, 恢复内核调度器的可抢占性.
访问其他per-CPU: per_cpu(variable, cpu_id)
4.动态per-cpu
产生:alloc_percpu(type) 释放:free_percpu(void *variable) 访问:per_cpu_ptr(void *variable, int cpu_id)
#C/C++##C++工程师##嵌入式##嵌入式工程师##Linux#