linux内核学习——内存管理

一、内核内存管理基础:

页:

内核把物理页作为内存管理的基本单位。

32位系统:4K / 页

64位系统:8K / 页

区:

由于硬件限制,内核不能对所有页一视同仁。linux必须处理如下硬件存在的缺陷而引起的内存寻址问题:

  • 一些硬件只能用某些特定内存地址来执行DMA(直接内存寻址)
  • 一些体系结构的内存物理寻址范围比虚拟寻址范围大得多。这样一些内存就不能永久映射到内核空间。

linux主要使用了四种区:

ZONE_DMA —— 这个区包含的页只能用来执行DMA操作

ZONE_DMA32 —— 和ZONE_DMA类似,但只能被32位设备访问

ZONE_NORMAL —— 这个区包含的页都是能正常映射的页

ZONE_HIGHEM —— 这个区包含“高端内存”,不能永久映射到内核地址空间


X86-32上的页
描述 物理内存
ZONE_DMA DMA使用的页  < 16M
ZONE_NORMAL 正常寻址的页 16M ~ 896M
ZONE_HIGHEM 动态映射的页 > 896M


二、内存操作函数:

以页为单位:

低级页分配方法
函数 描述
struct page * allock_page(gfp_mask) 只分配一页,返回指向页结构的指针
struct page * allock_page(gfp_mask, order)
分配2的order次方个页,返回指向第一个页结构的指针
unsigned long __get_free_page(gfp_mask) 只分配一页,返回指向企逻辑地址的指针
unsigned long __get_free_pages(gfp_mask, order) 分配2的order次方个页,返回指向第一页逻辑地址的指针
unsigned long get_zoned_page(gfp_mask) 只分配一页,让其内容填充0,返回指向企逻辑地址的指针


页释放函数
函数原型 描述
void __free_pages(struct page * page, unsigned int order) 释放page页地址开始的2的order次方个页
void free_pages(unsigned long addr, unsigned int order) 释放addr地址开始的2的order次方个页
void free_page(unsigned long addr) 释放addr地址开始的一个页

struct page * allock_pages(gfp_t gfp_mask, unsigned int order)

该函数分配2的order次方个连续的物理页,并返回指向第一个页的page结构体指针;如果出错返回NULL。

下面函数把给定的页转换成它的逻辑地址:

void * page_address(struct page * page)


e.g.获得8个页,然后释放:

unsigned long page;

page = __get_free_pages(GFP_KERNEL, 3);     //申请8个页

if (!page)

{

return -ENOMEM;        //没有足够内存

}

free_pages(page, 3);    //释放

GFP_KERNEL是gfp_mask标志的一种,后边有说明


以字节为单位:

按字节分配及释放内存函数
函数原型 描述
void * kmalloc(size_t, gfp_t flags) 按照flags标志分配至少size字节大小的内存,且物理连续,返回指向内存块的指针
void * vmalloc(unsigned long size) 按照flags标志分配至少size字节大小的内存,虚拟地址连续,物理地址不一定连续,返回指向内存块的指针
void kfree(const void *ptr) 释放由kmalloc申请的内存空间
void vfree(const void *addr) 释放由vmalloc申请的内存空间


kmalloc 和 vmalloc的区别在于:

kmalloc()分配的是物理地址连续的内存(逻辑地址自然也是连续的),该函数是否允许休眠通过其参数flags来决定。

vmalloc()函数只确保页在虚拟地址空间内是连续的,它通过分配非连续的物理内存块,再“修正”页表,把内存映射到逻辑地址空间的连续区域。

因此,该函数可能睡眠,不能在中断上下文进行调用,也不能从其他不允许组赛的情况下调用。

出于性能考虑,内核代码多用kmalloc()来获得内存。


三、gfp_mask标志:

不管是在低级页分配函数中,还是在kmalloc()中,都用到了分配器标志。这些标志可分为三类:行为修饰符、区段修饰符及类型。


行为修饰符表示你内核该如何分配所需内存,如:中断处理程序需要内核分配内存过程中不能睡眠。

常用的行为修饰符
标志 描述
 __GFP_WAIT 分配器可以睡眠
__GFP_IO 分配器可以启动磁盘IO
__GFP_FS 分配器可以启动文件系统IO
__GFP_HIGH 分配器可以访问紧急事件缓冲池


区修饰符表示从哪个区中进行分配,ZONE_DMA、ZONE_NORMAL还是ZONE_HIGHEM。

区修饰符
标志 描述
__GFP_DMA32 从ZONE_DMA分配
__GFP_DMA32 只在ZONE_DMA32分配
__GFP_HIGHMEM 从ZONE_HIGHMEM或ZONE_NORMAL分配


类型标志是行为修饰符和区修饰符的组合,如:GFP_KERNEL  =  (__GFP_WAIT  |  __GFP_IO  |  __GFP_FS)

常用的类型标志
标志 描述
GFP_ATOMIC 这个标志用在中断处理程序、下半部、持有自旋锁以及其他不能睡眠的地方
GFP_KERNEL 这是一种常规分配方式,可能会阻塞。这个标志在睡眠安全时用在进程上下文代码中,
为了获得调用者所需的内存,内核会尽力而为。这个标志应当是首选标志

四、slab层

请参考:

http://blog.sina.com.cn/s/blog_65373f1401017o4v.html



你可能感兴趣的:(linux,内存管理)