Keep looking Donot settle
分类: 嵌入式
2014-10-10 19:43:36
1. 页
内核把物理页作为内存管理的最小单位,尽管处理器的最小寻址单位通常为字,但是,内存管理单元(MMU)通常以页为单位进行处理。必须理解一点page结构与物理页相关,而非与虚拟页相关,物理页中存放的数据由于交换等原因,可能被交换出去,它们可能并不再和同一个page结构相关联,内核仅仅用这个数据结构来描述当前时刻物理页中存放的东西。这种数据结构的目的在于描述物理内存本身,而不是描述其中的数据。一般情况下32位体系结构,页的大小为4KB。而64位体系结构一般会支持8KB的页。
2.区
由于硬件的限制,内核并不能一视同仁的对待所有的页,有些页位于内存中特定的物理地址上,所以不能将其用于一些特定的任务,由于存在这种限制,所以内核把页划分为不同的区。
Linux内核使用了三种区:
ZONE_DMA -这个区包含的页用来执行DMA操作
ZONE_NORMAL-这个区包含的都是正常映射的页
ZONE_HIGHMEM-这个区包含"高端内存",其中的页并不能永久的映射到内核地址空间
在X86上:
ZONE_DMA <16MB
ZONE_NORMAL 16-896MB
ZONE_HIGHMEM >896MB
3.获得页与释放页
内核提供一种请求内存的底层机制,并提供了对它访问的几个接口,所有的这些接口都是以页为单位分配内存,定义于
struct page* alloc_pages(unsigned int gfp_mask,unsigned int order);
该函数分配2的order次幂连续的物理页,并返回一个指针,该指针指向第一个页的page结构体。如果出错,则返回空。
void *page_address(struct page* page);
该函数返回一个指针,指向当前物理页所在的逻辑地址。传递的参数是page结构体指针
这个地址是内核虚拟地址,即内核可以直接访问的地址。
unsigned long _ _get_free_pages(unsigned int gfp_mask,unsigned int order)
这个函数返回的所请求的页的内核空间的虚拟地址。
struct page* alloc_page(unsigned int gfp_mask)
unsigned long __get_free_page(unsigned int gfp_mask);
返回的是单页。
unsigned long get_zeroed_page(unsigned int gfp_mask);
这个函数与__get_free_page工作方式相同,只不过把分配好的页都填为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);
4. kmalloc与vmalloc函数
kmalloc:
kmalloc函数与用户空间的malloc一族函数非常类似,只不过它多了一个flags参数。
kmalloc函数是一个简单的接口,用以获得以字节为单位的一块内核内存。如果你需要整个页,那么,前面讨论的页可能是最好的选择。
kmalloc函数在
void *kmalloc(size_t size,int flags);
void kfree(const void* addr);
这个函数返回的是指向内存的内核逻辑地址的指针,其内存块大小至少为size大小。所分配的内存区在物理上是连续的。
vmalloc:
vmalloc函数类似于kmalloc,只不过前者分配的内存虚拟地址是连续的,而物理地址无需连续。kmalloc函数保证的页的物理地址是连续的,内核虚拟地址也是连续的,而vmalloc只保证页在虚拟地址空间是连续的,它通过分配非连续的物理内存块,再“修正”页表,把内存映射到逻辑地址空间的连续区域中,就能做到这点。
因此,vmalloc函数为了把物理上不连续的页转换成虚拟地址空间上连续的页,必须建立页表项。vmalloc获得的页必须一个一个的进行映射,因为它们在物理上是不连续的。这直接导致比直接内存映射大得多的TLB抖动。
void *vmalloc(unsigned long size);
void vfree(void *addr);
kmalloc与vmalloc返回的都是内核虚拟地址(内核可以访问的地址),这些地址对应着物理内存中的一个个页面,kmalloc得到的地址也称为“逻辑地址”,因为是连续的页,访问物理内存只需要一个偏移量计算即可。
关于Linux内存管理就介绍到这了。