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#
全部评论

相关推荐

点赞 评论 收藏
转发
4 9 评论
分享
牛客网
牛客企业服务