linux内核空间中申请内存涉及的函数主要有kmlloc()、__get_free_pages()和vmalloc()等。kmalloc()和__get_free_pages()申请的内存位于常规内存区和DMA的映射区,并且在物理上是连续的,它们与真是的物理区只存在一个固定的偏移量,存在着较为简单的转换关系。而vmalloc()分配的内存位于虚拟内存空间的连续的内存区域,实际上连续的虚拟内存在物理内存上并不连续。vmalloc在进行内存分配时会改变页表项,而kmlloc用的是开机就项映射好的常规内存和DMA区域的页表项。
(1) kmlloc()
void *kmlloc(size_t size,int flags);//size分配内存的大小,flags分配标志用来控制kmlloc的行为。
分配标志有以下几种:
GFP_KERNEL(常用):在内核空间的进程中分配内存,再申请内存时如果暂时不能满足进程进入睡眠等待页,将会阻塞,因此该标志不能用于中断上下文或持有自旋锁的情况下。
GFP_ATOMIC:在申请内存时如果不存在空闲页,则立即返回,因此该标志可以用于中断上下文或持有自旋锁的情况下。
GFP_USER: 为用户空间分配内存,可能会引起阻塞。
GFP_HIGHUSER:类似GFP_USER但是其从高端内存分配。
GFP_DMA:从DMA区域分配内存。
GFP_NOIO:不允许任何I/O初始化。
GFP_NOFS:不允许任何文件系统调用。
使用kfree()释放kmalloc()分配的内存。
(2) __get_free_pages()
__get_free_pages()系类函数/宏是linux内核最底层获取空闲空间的方法,因为底层使用buddy算法一2^n页为单位管理空闲内存,所以最底层内存的申请总是以2^N页为单位。
__get_free_pages()系列函数/宏本包括get_zeroed_page()、__get_free_page()和__get_free_pages()。
get_zeroed_page(unsigned int flags);//返回一个指向一个已经清零的页的指针。
__get_free_page(unsigned int flags);//该宏返回一个新页的指针但是不清零。
__get_free_pages(unsigned int flags,unsigned int order);//该函数分配order页并返回内存的首地址。
释放内存的函数有:void free_pages(unsigned long addr),void free_page(unsigned long addr,unsigned long order)。
(3)vmalloc()
vmalloc()一般为只存在软件的较大顺序缓冲区分配内存,其在分配内存时需要建立新的页表项,代价较大,并且其不能用在中断上下文和持有自旋锁的进程中。
void vmalloc(unsigned long size);//分配内存
void vfree(void *addr);//释放内存
(4)slab
如果完全使用以页为单位的内存分配回收机制容易造成内存的浪费,还有就是操作系统在运行过程中经常会有大量的重复的对象的建立和销毁。如果有合适的方法使相同类型的对象在前后两次的使用同一块内存空间或同类的内存空间 并且保留了基本的数据,则可以大大的提高效率。而slab算法就是针对上述特点设计。
①创建slab缓存
struct kmem_cache *kmem_cache_craete(const char *name,size_t size,size_t align,unsigned long flags, \
void (*ctor)(void*,struct kmem_cache*,unsigned long), \
void (*dtor)(void*,struct kmem_cache*,unsigned long));
kmem_cache_craete创建一个任意数目的全部同样大小的后备缓存。size要分被的每个数据块的大小,flags控制如何进行分配。
② 分配salb缓存
void *kmem_cache_alloc(struct kmem_cache *cachep,gfp_t flags);//在①创建的slab缓存区中分配一块内存并返回首指针。
③ 释放salb缓存
void kmem_cache_free(struct kmem_cache *cachep,void *objp);//释放有②分配的内存。
④ 回收sable缓存
int kmem_cache_destory(struct kmem_cache *cachep);//释放有①创建的缓存区。
(5)内存池
内存池是一种典型的用于分配大量小对象的后备缓存技术。
① mempool_t结构体
typedef struct mempool_s {
spinlock_t lock; /*保护内存池的自旋锁*/②创建内存池
mempool_t *mempool_create(int min_nr,mempool_alloc_t *alloc_fn,mempool_free_t *free_fn,void *pool_data);
min_tr:需要分配对象的数目。
alloc_fn和free_fn分别指向内存池机制提供的标准提供的对象分配和回收函数的指针。
pool_data:是分配和回收函数用到的指针,gfp_mask是分配标志。
③分配和回收对象
void *mempool_alloc(mempool_t *pool,int pfg_mask);
void mempool_free(void *element,mempool_t *pool);
④回收内存池
void mempool_destory(mempool_t *pool);
struct vm_area_struct
struct mm_struct * vm_mm; /*虚拟区间所在的地址空间*/
unsigned long vm_start; /*在vm_mm中的起始地址*/
unsigned long vm_end; /*在vm_mm中的结束地址 */
/* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next;
pgprot_t vm_page_prot; /*对这个虚拟区间的存取权限 */
unsigned long vm_flags; /*虚拟区间的标志. */
rb_node_t vm_rb;
/*
* For areas with an address space and backing store,
* one of the address_space->i_mmap{,shared} lists,
* for shm areas, the list of attaches, otherwise unused.
*/
struct vm_area_struct *vm_next_share;
struct vm_area_struct **vm_pprev_share;
/*对这个区间进行操作的函数 */
struct vm_operations_struct * vm_ops;
/* Information about our backing store: */
unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
units, *not* PAGE_CACHE_SIZE */
struct file * vm_file; /* File we map to (can be NULL). */
unsigned long vm_raend; /* XXX: put full readahead info here. */
void * vm_private_data; /* was vm_pte (shared mem) */
};
struct
vm_operations_struct {
void
(*open)(
struct
vm_area_struct * area);
void
(*close)(
struct
vm_area_struct * area);
int
(*fault)(
struct
vm_area_struct *vma,
struct
vm_fault *vmf);
/* notification that a previously read-only page is about to become
* writable, if an error is returned it will cause a SIGBUS */
int
(*page_mkwrite)(
struct
vm_area_struct *vma,
struct
page *page);
/* called by access_process_vm when get_user_pages() fails, typically
* for use by special VMAs that can switch between memory and hardware
*/
int
(*access)(
struct
vm_area_struct *vma, unsigned
long
addr,
void
*buf,
int
len,
int
write);