内存管理

内核将物理页作为内存管理的基本单位,而处理器最小的处理单位可能是一个字节或一个字。对于内存管理来说,页是最小的管理单元。MMU维护着以页为最小粒度的页表。不同的平台页的大小也不同。许多平台支持多种页大小。大部分32位平台拥有4KB个页,而64位平台拥有8KB个页。

 

区域(Zone

       由于硬件的限制,内核不能将所有的内存物理页一视同仁。有些物理页的地址只能用于特定的任务。正是由于这个原因,内核将物理页划分成区域。内核用区域来对具有类似属性的页进行分组。内核有4个主要的内存区域:

ZONE_DMA——可以执行DMA操作的区域。

ZONE_DMA32——ZONE_DMA类似,该区域包含可以执行DMA操作的页。这些页只能由32位设备访问。

ZONE_NORMAL——该区域包含了普通的、正常映射了的页。

ZONE_HIGHMEM——该区域包含了高内存,这些物理页不是永久性地映射到了内核的地址空间中。X86平台上的映射情况如下:

       底层页操作

       内核提供了一种底层机制来请求内存,以及几个访问内存的接口。所有这些接口分配的内存的粒度为页大小,声明在<linux/gfp.h>,核心函数为:

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

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

void * page_address(struct page *page)

该函数返回指向给定物理页当前对应的逻辑地址的指针。

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)

alloc_pages类似,只不过返回的是请求页的逻辑地址。

如果只请求一个页,可使用如下相应的函数:

struct page * alloc_page(gfp_t gfp_mask)

unsigned long __get_free_page(gfp_t gfp_mask)

如果需要返回零填充的页,使用函数:

unsigned long get_zeroed_page(unsigned int gfp_mask)

与函数__get_free_page()类似,只不过返回的是零填充后的页。

       释放页

       下面的一些函数用于释放不再需要的页:

void __free_pages(struct page *page, unsigned int order)

void free_pages(unsigned long addr, unsigned int order)

void free_page(unsigned long addr)

       kmalloc()

       kmalloc()函数的操作类似于用户空间的malloc(),只是多了一个flags参数。kmalloc()函数是一个获取以字节为单位的内核内存的简单接口。

void * kmalloc(size_t size, gfp_t flags)

该函数返回指向某个内存区域的指针,该内存区域在物理上是连续的。

       kfree()

kfree()释放由kmalloc()分配的内核内存空间,其函数原型如下:

void kfree(const void *ptr)

vmalloc()

       vmalloc()分配一段在物理上不连续,但在虚拟地址空间上是连续的内存。它一般用于分配较大的内存空间时。其函数原型如下:

       void * vmalloc(unsigned long size)

       该函数可以会休眠,所以不能在中断上下文中使用或其他不能休眠的情形。

       出于性能上的考虑,在内核代码中,分配内存时一般使用kmalloc()函数。

       vfree()

       该函数用于释放由vmalloc()函数分配的内存空间。其函数原型如下所示:

void vfree(const void *addr)

内核栈

       内核栈占据一个或二个物理页,取决于编译时的配置选项。这些栈的大小从4KB16KB大小不等。历史上,中断处理程序与进程共享一个栈。当启用了单页栈后,中断处理函数拥有了自己的栈。

       由于内核栈的大小限制,所以在内核函数中,尽量控制栈变量的大小和数量,避免在一个函数内部定义很大数组。

       高内存映射

       X86平台上,物理地址超过896M的都慎于高内存。这些地址并不永久地或自动地映射到内核地址空间。这些物理面必须映射到内核的逻辑地址空间。在X86平台上,高内存地址通常映射到了处于3G4G之间的内存地址。

       为了将一个指定的page结构映射到内核的地址空间,使用如下函数:

void *kmap(struct page *page)

该函数可用于低内存地址或高内存地址的物理页映射。当物理页处于低内存,该函数返回该页的虚拟地址。当物理页处于高内存时,将创建一个永久映射,并返回返回映射后的地址。

void kunmap(struct page *page)

该函数解除映射。kmap()kunmap()函数均不能用于中断上下文中。

       临时映射

       有时,映射建立必须发生在中断上下文中,这时可以使用另外一对函数。

void *kmap_atomic(struct page *page, enum km_type type)

void kunmap_atomic(void *kvaddr, enum km_type type)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值