Linux内核之内存管理

来源:互联网 发布:恒指期货实时行情数据 编辑:程序博客网 时间:2024/05/18 02:49

一、页page

内核把物理页作为内存管理的基本单元。内存管理单元(MMU)通常以页为单位进行处理。从虚拟内存的角度看,页就是最小单位。
32位体系结构支持4KB的页,而64位的体系结构支持8KB的页。
内核用struct page结构来表示系统中的每个物理页。

二、区zone

由于硬件的限制,内核就把所有的页划分成不同的区(zone),Linux主要有四种分区:

  • ZONE_DMA–该区包含的页能用来执行DMA操作
  • ZONE_DMA32–也可用来执行DMA操作,但是只能被32位设备访问
  • ZONE_NARMAL–该区包含的是能正常映射的页
  • ZONE_HIGHMEM–高端内存,并不能永久映射到内核地址空间

x86-32上,分区情况:

区 描述 物理内存 ZONE_DMA DMA使用的页 <16M ZONE_NORMAL 正常可寻址的页 16~896M ZONE_HIGHMEM 动态映射的页 大于896M

三、获得页

static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)

该函数分配2的order次方个连续的物理页,返回指向第一个页的结构体的指针。

void *page_address(const struct page *page)

将指定的页转换成它的逻辑地址。

若无需用到struct page,就可以调用:

extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);//注意,该函数要进行错误检查,分配失败必须进行相应处理

该函数直接返回请求的第一个页的逻辑地址。

如果只需要一页,就可以用一下两个函数:

struct page * alloc_page(gdp_t gfp_mask)unsigned long __get_free_page(gfp_t gfp_mask);

如果你需要让返回的页的内容全为0,请用下面这个函数:

unsigned long get_zeroed_page(gfp_t gfp_mask);

释放页:

void __free_pages(struct page *page, unsigned int order);void free_pages(unsigned long addr, unsigned int order);void free_page(unsigned long addr);

释放时需要谨慎,仅释放属于你的页,释放错了地址或者用错了order值可能导致系统崩溃。

四、kmalloc

kmalloc()函数与用户空间的malloc函数类似,只不过多了一个flags参数。该函数是申请获得以字节为单位的一块内核内存。分配的内存在物理上是连续的。

void *kmalloc(size_t size, gfp_t flags)void kfree(const void *ptr)

gfp_mask标志:
这些标志分为三类:行为修饰符、区修饰符、类型标志

行为标志 描述 __GFP_WAIT 分配器可以睡眠 __GFP_HIGH 分配器可以访问紧急事件缓冲池 __GFP_IO 分配器可以启动磁盘I/O __GFP_FS 分配器可以启动文件系统I/O __GFP_COLD 分配器应该使用高速缓存中快要淘汰出去的页 __GFP_NOWARN 分配器将不打印失败警告 __GFP_REPEAT 分配器在分配失败时重复进行分配,但是这次分配还存在失败的可能 __GFP_NOFALL 分配器将无限的重复进行分配。分配不能失败 __GFP_NORETRY 分配器在分配失败时不会重新分配 __GFP_NO_GROW 由slab层内部使用 __GFP_COMP 添加混合页元数据,在 hugetlb 的代码内部使用 区标志 描述 __GFP_DMA 从 ZONE_DMA 分配 __GFP_DMA32 只在 ZONE_DMA32 分配 (注1) __GFP_HIGHMEM 从 ZONE_HIGHMEM 或者 ZONE_NORMAL 分配 类型标志 描述 GFP_ATOMIC 这个标志用在中断处理程序,下半部,持有自旋锁以及其他不能睡眠的地方 GFP_NOWAIT 与 GFP_ATOMIC 类似,不同之处在于,调用不会退给紧急内存池。这就增加了内存分配失败的可能性 GFP_NOIO 这种分配可以阻塞,但不会启动磁盘I/O。这个标志在不能引发更多磁盘I/O时能阻塞I/O代码,可能会导致递归 GFP_NOFS 这种分配在必要时可能阻塞,也可能启动磁盘I/O,但不会启动文件系统操作。这个标志在你不能再启动另一个文件系统的操作时,用在文件系统部分的代码中 GFP_KERNEL 这是常规的分配方式,可能会阻塞。这个标志在睡眠安全时用在进程上下文代码中。为了获得调用者所需的内存,内核会尽力而为。这个标志应当为首选标志 GFP_USER 这是常规的分配方式,可能会阻塞。用于为用户空间进程分配内存时 GFP_HIGHUSER 从 ZONE_HIGHMEM 进行分配,可能会阻塞。用于为用户空间进程分配内存 GFP_DMA 从 ZONE_DMA 进行分配。需要获取能供DMA使用的内存的设备驱动程序使用这个标志。通常与以上的某个标志组合在一起使用。

五、vmalloc()

vmalloc函数的工作方式与kmalloc类似,只不过vmalloc分配的虚拟地址是连续的,但物理地址无需连续。
通过分配非连续的物理内存块,再修正页表,把内存映射到连续的虚拟地址空间中。这就带来一些消耗,带来性能上的影响,仅仅在不得已时才会使用。

void *vmalloc(unsigned long size)void vfree(const void *addr)
0 0
原创粉丝点击