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()函数源码分析:

浙公网安备 33010602011771号