页框用page描述符描述。所有的page放在mem_map数组中,virt_to_page产生线性地址对应的页描述符地址, pfn_to_page产生与页框号对应的页描述符地址。
linux内存被划成几个节点,节点包含几个管理区, 包含第一个页框的页框号, 页描述符的数组,在x86上只使用一个结点,
x86上有三种内存管理区:ZONE_DMA, ZONE_NORMAL, ZONE_HIGHMEM.
管理区描述符包含所属节点, 管理区的第一个页描述符指针, 第一个页框号等,
保留的页框池用于中断等原子内存请求操作时内存不足的情况,在zone_dma, zone_normal区按照他们的比例分配。
分区页框分配器包含管理区分配器, 每cpu页框高速缓存, 伙伴系统,
每cpu页框高速缓存只分配一个页框, 它基于伙伴系统
伙伴系统用于分配连续的内存区
请求页框的函数: alloc_pages(返回页框描述符地址), alloc_page, __get_free_pages(返回线性地址), get_zeroed_page, __get_dma_pages,
高端内存无直接的线性地址, 只能用alloc_pages()返回页框描述符地址,内核线性地址空间的最后128m中的部分用于映射高端内存页框, 这种映射是临时的(不够用),
内核用三种机制将页框映射到高端内存(获得线性地址):永久, 临时, 非连续。
永久:PKMAP_BASE, kmap()
临时:kmap_atomic(), 在FIX_KMAP_BEGIN处开始
伙伴系统:
把空闲页分为11个块链表, 如果某链表无足够的内存, 就到更大一级分配,并把大一级的块重新插入到小块。__rmqueue()
__free_pages_bulk()释放, 释放会试图把释放的块与大块合并
每cpu页框高速缓存, 用于分配单个页框请求, 分为冷热缓存(与硬件高速缓存行有关),bufferred_rmqueue()分配该页框, 如果每cpu页框高速缓存中的页框数count小于等于low, 反复调用__rmqueue()从伙伴系统中分配batch各单一页框。free_hot_cold_page)释放页框到伙伴系统。
管理区分配器__alloca_pages(): 执行多次扫描以得到需要的内存。
slab管理器建立在高速缓存基础上, 分为专用和普通高速缓存,
普通:(系统初始化期间由kmem_cache_init(), kmem_cache_sizes_init()来建立)
第一个称为kmem_cache, cache_cache变量包含它的第一个高速缓存描述符
其它包含在成几何分布的malloc_sizes的表中,分为两种: dma和normal
专用:(由kmem_cache_create在模块初始化的时候创建, 由kmem_cache_destroy在模块卸载的时候销毁)
在普通高速缓存基础上建立
cache_grow分配slab缓存, slab_destroy()释放slab缓存
slab需要着色算法避免映射到同样的内存行
kmem_cache_alloc()分配slab对象
kmem_cache_free()释放slab对象
kmalloc/kfree用于从普通高速缓存分配和释放通用slab对象
内存池与保留页框不同, 后者用于中断等原子内存请求, 虽然前者也用于紧急内存分配, 内存池一般用来保存slab对象,当然也用于一般类型的动态内存。需要注册alloca和free方法。方法通常是mempool_alloc_slab()/mempool_free_slab(),
mempool_create()创建新内存池,注册alloca/free方法, mempool_destroy相反
mempool_alloc调用alloc方法, mempool_free调用free方法
非连续内存是高端内存的一种, 在VMALLOC_START(距离high_memory开始8m的地方)到VMALLOC_END(距离PKMAP_BASE8k)这段区域,
vmalloc分配:调用kmalloc分配存放page的数组, 用alloc_page从high mem分配page, 用map_vm_area()映射线性地址。
vfree释放