一、基本概念
页:
内核把物理页作为内存管理的基本单元。MMU(内存管理单元)是管理内存,并把虚拟地址转换为物理地址的硬件。MMU已页大小为单位管理系统中的也不。
从虚拟内存的角度来看,页就是最小单位。当时必须理解一点,page结构与物理页相关,并非与虚拟页相关。
系统中的每个物理页都要分配一个这样的结构体。
struct page
{
unsigned long flags; //页的状态,比如页是不是脏的,是不是被锁定在内存中
atomic_t _count; //页的引用计数,一般调用page_count()函数来检查,不直接访问
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual; //页的虚拟地址
......
}
区:
内核把页划分为不同 的区,内核使用区对具有相似特征的页进行分组。
Linux中主要使用四种区:
ZONE_DMA DMA使用的页
ZONE_DMA32 DMA使用的页,只能被32位设备访问
ZONE_NORMAL 正常可寻址的页
ZONE_HIGHEM 动态映射的页
在x86-32上,ZONE_DMA : <16MB,ZONE_NORMAL: 16~896MB; ZONE_HIGHEM: > 896MB
每个区都使用struct zone表示,结构体较大,在<linux/mmzone.h>中定义
二、内存分配
1、获取页
alloc_page(gfp_mask) 只分配一页,返回指向页结构的指针
alloc_pages(gfp_mask, order) 分配2^order个页,返回指向页结构的指针
__get_free_page(gfp_mask) 只分配一页,返回指向其逻辑地址的指针
__get_free_pages(gfp_mask, order) 分配2^order个页,返回指向其逻辑地址的指针
get_zeroed_page(gfp_mask) 只分配一页,让内容填充0,返回指向其逻辑地址的指针
void _free_pages(struct page*page, unsigned int order);
void free_pages(unsigned long addr, unsigned int order);
void free_page(unsigned long addr);
2、获取较少字节的连续物理地址内存
void *kmalloc(size_t size, gfp_t flags);
void kfree(const void *ptr);
3、获取非连续的物理地址内存
void *vmalloc(unsigned long size);
void vfree(const void *addr);
4、slab分频器
struct kmem_cache *kmem_cache_create(const char *name, //高速缓存的名字
size_t size, //高速缓存中每个元素的大小
size_t align, // slab内第一个对象的偏移,用了确保在业内进行特定的对齐
unsigned long flags,
void (*octor)(void *)); // 高速缓存的构造函数,在新的页追加到高速缓存时,构造函数才被调用
int kmen_cache_destroy(struct kmem_cache (cachep);
// 从缓存中分配对象
void *keme_cache_alloc( struct kmem_cache , gfp_t flags);
// 释放对象
void keme_cache_free( struct kmem_cache , void *objp);