linux内核——虚拟内存分配一

标签:
linux物理内存 |
分类: linux学习笔记 |
一 页
地址,通常以页为单位进行处理。MMU以页大小为单位来管理系统中的也表。
内核用相应的数据结构表示系统中的每个物理页:
<linux/mm_types.h>
struct page {}
系统中每一个物理页都要分配这样一个结构体,进行内存管理。
二 区
一些硬件只能用某些特定的内存来执行DMA(直接内存访问)
一些体系结构其内存的物理寻址范围必须你寻址范围大得多。这样导致一些内存不能永久映射到内核空间上。
ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。
在x86结构中,三种类型的区域如下:
ZONE_DMA
ZONE_NORMAL
ZONE_HIGHMEM
同样每个区包含众多页,形成不同内存池,按照用途进行内存分配。用相应的数据结构来表示区:
<linux/mmzone.h>
struct zone {}
三 获取页/内存
static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)——分配2的order次方个连续的物理页,返回指向第一个页的page结构体指针。
void *page_address(const struct page *page)——返回指向给定物理页当前所在的逻辑地址
unsigned long get_free_page(unsigned int gfp_mask)——分配一页的内存空间,返回虚拟地址
extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)——分配2的order次方个页,并返回虚拟首地址
extern unsigned long get_zeroed_page(gfp_t gfp_mask)——分配一页物理内存并将该物理页全部清零,最后返回一个虚拟(线形)地址。
释放内存:
void kfree(const void *objp)
void free_page(unsigned long addr);
void free_pages(unsigned long addr, unsigned long order)——注意order和你分配的页相等
内存的释放要准确!
分配内存物理上连续。
gfp_t标志:表明分配内存的方式。如:
GFP_ATOMIC:分配内存优先级高,不会睡眠
GFP_KERNEL:常用的方式,可能会阻塞。
2
vmalloc
void *vmalloc(unsigned long size)
void vfree(const void *addr)
vmalloc()与kmalloc方式类似,vmalloc分配的内存虚拟地址是连续的,而物理地址则无需连续,与用户空间分配函数一致。
vmalloc通过分配非连续的物理内存块,在修正页表,把内存映射到逻辑地址空间的连续区域中,虚拟地址是连续的。是否必须要连续的物理地址和具体使用场景有关。在不理解虚拟地址的硬件设备中,内存区都必须是连续的。通过建立页表转换成虚拟地址空间上连续,肯定存在一些消耗,带来性能上影响。所以通常内核使用kmalloc来申请内存,在需要大块内存时使用vmalloc来分配。
四 slab层
闲链表——内存池。当不使用的已分配的内存时,将其放入内存池中,而不是直接释放掉。
slab层的设计实现
slab数据结构和接口:
每个高速缓存用kmem_cache结构来表示:
缓存区包含三种slab:满,未满,空闲
struct kmem_list3 {
};
每一个slab包含多个对象:
struct slab {
};
相关接口:mm/slab.c
struct kmem_cache *kmem_cache_create (
const char *name,
size_t size,
size_t align,
unsigned long flags,
void (*ctor)(void *))
name 参数定义了缓存名称,proc 文件系统(在 /proc/slabinfo 中)使用它标识这个缓存。
size 参数指定了为这个缓存创建的对象的大小,
align 参数定义了每个对象必需的对齐。
flags 参数指定了为缓存启用的选项:
kmem_cache_create 的部分选项(在 flags 参数中指定)
SLAB_RED_ZONE
SLAB_POISON
SLAB_HWCACHE_ALIGN
ctor 和 dtor 参数定义了一个可选的对象构造器和析构器。构造器和析构器是用户提供的回调函数。当从缓存中分配新对象时,可以通过构造器进行初始化。
要从一个命名的缓存中分配一个对象,可以使用 kmem_cache_alloc 函数。
void kmem_cache_alloc( struct kmem_cache *cachep, gfp_t flags );
这个函数从缓存中返回一个对象。注意如果缓存目前为空,那么这个函数就会调用 cache_alloc_refill 向缓存中增加内存。
kmem_cache_alloc 的 flags 选项与 kmalloc 的
cachep:所建立的缓存区
flags参数:
GFP_USER 为用户分配内存(这个调用可能会睡眠)。
GFP_KERNEL
GFP_ATOMIC
GFP_HIGHUSER
五 高端内存的映射
永久映射:可能会阻塞
映射一个给定的page结构到内核地址空间:
void *kmap(struct page *page)
解除映射:
void kunmap(struct page *page)
临时映射:不会阻塞
void *kmap_atomic(struct page *page)
六 分配函数的选择
l
l
l
l
Linux高端内存:
http://ilinuxkernel.com/?p=1013
Linux slab 分配器剖析:
https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/