1、Linux内核内存管理

1、页框:在Linux内核中,所有的物理地址被4K大小的内存块划分,这4K大小的内存块,使用一个结构体struct page来管理;其中每个内存块称为一个页框;因此在Linux内核中,内存管理最小单位是页框;

对于一些特定的应用需求,应用需要开辟一块连续的内存大小;为了针对这样的需求,出现了伙伴算法;

2、伙伴算法:在内核中把页框使用具有11个节点的链表,把页框管理起来,每个链表节点上的页框大小都是固定的。在第n个节点上具有的页框大小为2^n个。因此使用这样的链表可以表示一段连续的内存;这样一个节点最大可管理的内存大小为2^10*4K=4M;

// 分配2^order个连续的物理页,返回只一个结构体指针  
//linux-3.19.3/include/linux/gfp.h
static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
    return alloc_pages_current(gfp_mask, order);
}
// 返回page页面所映射的虚拟地址
// linclude/linux/mm.h
void *page_address(struct page *page);

 3、物理页、slab、高速缓存之间关系:

  多个物理页经过slab算法,将许多的物理页管理起来,所形成的整体形成高速缓存;

  slab由一个或多个物理上连续的页组成,每个高速缓存由多个slab组成;

     

  slab的三种状态:

  1、slabs_full:slab管理的物理页对象已经分配完了,没有可用对象;

  2、slabs_partial:使用了一部分对象;

  3、slabs_free:管理物理页的对象都空闲,没有正在使用的;

     

 

 

 4、slab机制解决哪些问题:

  1、减少伙伴算法在分配内存时产生的内部内存碎片;

  2、将频繁使用的对象缓存起来,减少分配,初始化和释放对象的时间开销;

  3、通过着色技术调整以更好地使用硬件高速缓存;

5、其他内存机制:

  slob、slub:

6、高速缓存的使用:

  在内核中已经有一些创建好的系统高速缓存,可以使用cat /proc/slabinfo查看系统高速缓存。使用下面函数我们可以创建自己的高速缓存; 

// linux-3.19.3/mm/slab_common.c
struct kmem_cache * kmem_cache_create (const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *))

  创建好高速缓存后,可以使用下面函数获取到上面创建的高速缓存。

// llinux-3.19.3/mm/slab.c
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t f lags)

 其中的gfp_t f lags参数表明是在不同的场景,中断中不允许睡眠,DMA中申请内存,或者普通场景申请内存;

  使用完缓存后,释放掉创建的缓存:

//linux-3.19.3/mm/slab_common.c
int kmem_cache_destroy (kmem_cache_t * cachep)

  上面的分配内存使用最终使用下面这个函数:

// linux-3.19.3/mm/slab_common.c
static __always_inline void* slab_alloc(struct kmem_cache* cachep, gfp_t flags,unsigned long caller);

7、更上层的内存管理:

  kmalloc():在内核空间、物理地址分配连续的内存大小;

  kzallo(): 在kmalloc()基础上,将分配的内存内容全部置0;

  vmalloc(): 在虚拟空间分配,分配的内存不需要连续的;

  给硬件分配的内存需要连续的,给逻辑代码分配的内存空间不需要连续;

 8、Linux中内核常见的内存分配函数:

   其中在驱动中,常用的是kmalloc()函数

 

9、Kmalloc()函数源码分析:

  

 

posted @ 2021-07-11 18:33  笑不出花的旦旦  阅读(215)  评论(0)    收藏  举报