Linux驱动技术(一) _内存申请

系统 Linux 系统运维
内核程序也需要动态的分配内存,不同的是,内核进程可以控制分配的内存是在用户空间还是内核空间,前者可以用于给用户空间的堆区分配内存,eg,用户进程的用户空间的malloc最终就会通过系统调用回调内核空间的内存分配函数,此时该内存分配函数就属于该用户进程,可以给在该用户进程的堆区分配空间并返回,最终使得一个用会进程在自己的用户空间获得内存分配;后者只在内核空间分配,所以用户进程不能直接访问该空间,所以多用在满足内核程序自身的内存需求。

先上基础,下图是Linux的内存映射模型

  • 每一个进程都有自己的进程空间,进程空间的0-3G是用户空间,3G-4G是内核空间
  • 每个进程的用户空间不在同一个物理内存页,但是所有的进程的内核空间对应同样的物理地址
  • vmalloc分配的地址可以高端内存,也可以是低端内存
  • 0-896MB的物理地址是线性映射到物理映射区的。  

Linux的内存映射模型 

内存动态申请

和应用层一样,内核程序也需要动态的分配内存,不同的是,内核进程可以控制分配的内存是在用户空间还是内核空间,前者可以用于给用户空间的堆区分配内存,eg,用户进程的用户空间的malloc最终就会通过系统调用回调内核空间的内存分配函数,此时该内存分配函数就属于该用户进程,可以给在该用户进程的堆区分配空间并返回,最终使得一个用会进程在自己的用户空间获得内存分配;后者只在内核空间分配,所以用户进程不能直接访问该空间,所以多用在满足内核程序自身的内存需求,下面是Linux内核空间申请内存常用API:

kmalloc - kfree

kmalloc申请的内存在物理内存上是连续的,他们与真实的物理地址只有一个固定的偏移,因此存在简单的转换关系。这个API 多用来申请不到一个page大小的内存。kmalloc的底层需要调用__get_free_pages,参数中表示内存类型的gtp_t flags正是这个函数的缩写,常用的内存类型有GFP_USER,GFP_KERNEL,GFP_ATOMIC几种。

  • GFP_USER表示为用户空间页分配内存,可以阻塞;
  • GFP_KERNEL是最常用的flag,注意,使用这个flag来申请内存时,如果暂时不能满足,会引起进程阻塞,So,一定不要在中断处理函数,tasklet和内核定时器等非进程上下文中使用GFP_KERNEL!!!
  • GFP_ATOMIC就可以用于上述三种情境,这个flag表示如果申请的内存不能用,则立即返回。
  1. /** 
  2.  * kmalloc - allocate memory 
  3.  * @size: how many bytes of memory are required. 
  4.  * @flags: the type of memory to allocate. 
  5.  * The @flags argument may be one of
  6.  * %GFP_USER - Allocate memory on behalf of user.  May sleep. 
  7.  * %GFP_KERNEL - Allocate normal kernel ram.  May sleep. 
  8.  * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools. 
  9.  *  
  10.  * For example, use this inside interrupt handlers. 
  11.  */ 
  12. void *kmalloc(size_t size, gfp_t flags); 
  13. /** 
  14.  * kfree - free previously allocated memory 
  15.  * @objp: pointer returned by kmalloc. 
  16.  * If @objp is NULLno operation is performed. 
  17.  */ 
  18. void kfree(const void *objp);  

同系列API还有

  1. void *kzalloc(size_t size, gfp_t flags)     

__get_free_pages - free_pages

__get_free_pages()与kmalloc()一样是物理连续的内存,这一系列函数是Linux内核中***层的用于获取空闲内存的方法,因为底层的buddy算法都是以(2^n)×PAGE_SIZE来管理内存的,所以他们总是以页为单位分配内存的

  1. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)  void free_pages(unsigned long addr, unsigned int order)  

同系列API还有

  1. unsigned long __get_free_page(gfp_t gfp)        unsigned long get_zeroed_page(gfp_t gfp_mask)    struct page *alloc_pages(gfp_t gfp_mask, unsigned int order
  1. void free_page(unsigned long addr) 

vmalloc - vfree

vmalloc在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,所以vmalloc申请的虚拟内存和物理内存之间也就没有简单的换算关系,正因如此,vmalloc()通常用于分配远大于__get_free_pages()的内存空间,它的实现需要建立新的页表,此外还会调用使用GFP_KERN的kmalloc,so,一定不要在中断处理函数,tasklet和内核定时器等非进程上下文中使用vmalloc!

  1. /**      
  2.  * vmalloc  -  allocate virtually contiguous memory 
  3.  * @size:          allocation size 
  4.  * Allocate enough pages to cover @size from the page level allocator and map them into contiguous kernel virtual space
  5.  */void *vmalloc(unsigned long size)   /** 
  6.  *      vfree  -  release memory allocated by vmalloc() 
  7.  *      @addr:          memory base address 
  8.  */void vfree(const void *addr)   

同系列的API还有

  1. /** 
  2.  * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable) 
  3.  * @size:          allocation size 
  4.  * Allocate enough 32bit PA addressable pages to cover @size from the page level allocator and map them into contiguous kernel virtual space
  5.  */void *vmalloc_32(unsigned long size)   

slab缓存

我们知道,页是内存映射的基本单位,但内核中很多频繁创建的对象所需内存都不到一页,此时如果仍然按照页映射的方式,频繁的进行分配和释放就会造成资源的浪费,同时也会降低系统性能。为了解决的这样的问题,内核引入了slab机制,使对象在前后两次被使用时被分配在同一块内存或同一类内存空间,且保留了基本的数据结构,就可以大大提高效率。kmalloc的底层即是使用slab算法管理分配的内存的。注意,slab依然是以页为单位进行映射,只是映射之后分割这些页为相同的更小的单元,从而节省了内存。slab分配的单元不能小于32B或大于128K。

  1. /** 
  2.  * kmem_cache_create - 创建slab缓存对象 
  3.  * @name:slab缓存区名字, 
  4.  * @size:slab分配的缓存区的每一个单元的大小 
  5.  * @align:缓存区内存的对齐方式,一般给0 
  6.  * @flags:控制分配的位掩码, 
  7.  * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) to catch references to uninitialised memory. 
  8.  * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check for buffer overruns. 
  9.  * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware cacheline.  This can be beneficial if you're counting cycles as closely as davem. 
  10.  * %SLAB_CACHE_DMA - Use GFP_DMA memory 
  11.  * %SLAB_STORE_USER - Store the last owner for bug hunting 
  12.  *define SLAB_PANIC - Panic if kmem_cache_create() fails  
  13.  */struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *))/** 
  14.  * kmem_cache_alloc - Allocate an object from this cache.  
  15.  * @cachep: The cache to allocate from
  16.  * @flags: See kmalloc(). 
  17.  * The flags are only relevant if the cache has no available objects. 
  18.  */void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)  /** 
  19.  * kmem_cache_free - Deallocate an object 
  20.  * @cachep: The cache the allocation was from
  21.  * @objp: The previously allocated object. 
  22.  * Free an object which was previously allocated from this cache. 
  23.  */void kmem_cache_free(struct kmem_cache *cachep, void *objp)  void kmem_cache_destroy(struct kmem_cache *s)   

范例

  1. //创建slab对象 
  2.  
  3. struct kmem_cache_t *xj_sbcache; 
  4. xj_sbcache = kmem_cache_create("xjslab",sizeof(struct xj_unit_t),0,SLAB_CACHE_DMA|SLAB_PANIC,NULL,NULL);//分配slab缓存 
  5.  
  6. struct xj_unit_t *xj_unit; 
  7. xj_unit = kmem_cache_alloc(xj_sbcache,GFP_KERNEL); 
  8. /* 使用slab缓存 */ 
  9. /* 释放slab缓存 */ 
  10.  
  11. kmem_cache_free(xj_sbcache, xj_unit); 
  12. /* 销毁slab缓存 */ 
  13.  
  14. kmem_cache_destroy(xj_sbcache);  

内存池

除了slab机制,内核还提供了传统的内存池机制来管理小块内存的分配。内存池主要是用来解决可能出现的内存不足的情况,因为一个内存池在创建的时候就已经分配好了一内存,当我们用mempool_alloc向一个已经创建好的内存池申请申请内存时,该函数首先会尝试回调内存池创建时的分配内存函数,如果已经没有内存可以分配,他就会使用内存池创建时预先分配的内存,这样就可以避免因为无内存分配而陷入休眠,当然,如果预分配的内存也已经使用完毕,还是会陷入休眠。slab机制的目的是提高内存使用率以及内存管理效率,内存池的目的是避免内存的分配失败。下面是内核中提供的关于内存池的API 

  1. /**      
  2.  * mempool_create - create a memory pool 
  3.  * @min_nr:    the minimum number of elements guaranteed to be  allocated for this pool. 
  4.  * @alloc_fn:  user-defined element-allocation function
  5.  * @free_fn:   user-defined element-freeing function
  6.  * @pool_data: optional private data available to the user-defined functions. 
  7.  *               
  8.  * this function creates and allocates a guaranteed size, preallocated memory pool. The pool can be used from the mempool_alloc() and mempool_free() functions.  
  9.  * This function might sleep. Both the alloc_fn() and the free_fn() functions might sleep - as long as the mempool_alloc() function is not called from IRQ contexts. 
  10.  */ 
  11. mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data) 
  12.  
  13. /**      
  14.  * mempool_alloc - allocate an element from a specific memory pool 
  15.  * @pool:pointer to the memory pool which was allocated via mempool_create(). 
  16.  * @gfp_mask:  the usual allocation bitmask. 
  17.  * this function only sleeps if the alloc_fn() function sleeps or returns NULL. Note that due to preallocation, this function never* fails when called from process contexts. (it might fail if called from an IRQ context.) 
  18.  */      
  19. void * mempool_alloc(mempool_t *pool, gfp_t gfp_mask)     
  20.  
  21. /** 
  22.  * mempool_free - return an element to the pool. 
  23.  * @element:   pool element pointer. 
  24.  * @pool:pointer to the memory pool which was allocated via mempool_create(). 
  25.  * 
  26.  * this function only sleeps if the free_fn() function sleeps. 
  27.  */      
  28. void mempool_free(void *element, mempool_t *pool)     
  29.  
  30. /** 
  31.  * mempool_destroy - deallocate a memory pool 
  32.  * @pool:pointer to the memory pool which was allocated via mempool_create(). 
  33.  * 
  34.  * Free all reserved elements in @pool and @pool itself.  This function only sleeps if the free_fn() function sleeps. 
  35.  */      
  36. void mempool_destroy(mempool_t *pool)   

 

责任编辑:庞桂玉 来源: 嵌入式Linux中文站
相关推荐

2017-03-01 12:36:15

Linux驱动技术内存

2022-07-10 20:47:39

linux中虚拟内存

2017-02-28 17:46:15

Linux驱动技术并发控制

2019-03-20 14:29:46

Linux虚拟内存

2017-03-01 14:46:53

Linux驱动技术异步通知技术

2017-03-01 13:06:39

Linux驱动技术DMA编程

2022-05-10 08:49:46

设备驱动Linux

2017-03-01 16:40:12

Linux驱动技术设备阻塞

2021-04-12 12:00:13

Linux运维Linux系统

2020-06-28 09:30:37

Linux内存操作系统

2012-09-29 09:00:25

2021-11-12 11:28:01

Linux 内核驱动Linux 系统

2021-01-18 08:23:23

内存时底层CPU

2012-01-11 11:07:04

JavaJVM

2012-05-28 15:49:06

Linux凯迪拉克

2021-11-22 08:14:23

Linux Linux驱动Linux 系统

2021-05-12 18:22:36

Linux 内存管理

2022-07-28 08:00:00

Buddy算法内存系统

2018-10-10 14:14:51

Linux内存映射

2023-09-12 07:31:32

内存LyMemoryWIN10
点赞
收藏

51CTO技术栈公众号