Linux内存管理内核API函数alloc_pages( )

本文详细介绍了alloc_pages函数的功能和使用方法,包括输入参数gfp_mask和order的具体含义,以及返回值的意义。并通过一个实例演示了如何使用该函数分配连续的物理页,并展示了如何获取分配的物理页的相关信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.163.com/chujb_chen/blog/static/10571112013392331217/


函数功能描述

       alloc_pages( )函数以gfp_mask分配方式分配2的order次方(1<<order)个连续的物理页。 

输入参数说明

       gfp_mask: 是分配标志,内核分配内存有多种方式,该参数告诉内核如何分配以及在哪分配所需的内存,内存分配最终总是调用 __get_free_pages( ) 来实现,这也是 GFP_ 前缀的由来。其中分配标志(gfp_mask)可以取以下各值:       

GFP_KERNEL 

该分配方式最常用,是内核内存的正常分配,它可能睡眠。

GFP_ATOMIC

该分配方式常用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠。

GFP_USER 

用来为用户空间分配内存页,可能睡眠。

GFP_HIGHUSER 

类似GFP_USER,如果有高端内存,就从高端内存分配页。

GFP_NOIO 

GFP_NOFS 

功能类似于GFP_KERNEL,但是为内核分配内存的工作增加了限制。具有GFP_NOFS 的分配不允许执行任何文件系统调用,而 GFP_NOIO 禁止任何 I/O 初始化。它们主要用在文件系统和虚拟内存代码,那里允许分配休眠,但不应发生递归的文件系统调用。

 

有的标志用双下划线做前缀,他们可与上面标志“或”起来使用,以控制分配方式:

__GFP_DMA 

要求分配可用于DMA的内存。

__GFP_HIGHMEM 

分配的内存可以位于高端内存。

__GFP_NOWARN 

当一个分配无法满足,阻止内核发出警告(使用 printk )。

__GFP_HIGH 

高优先级请求,允许为紧急状况消耗被内核保留的最后一些内存页。

__GFP_REPEAT 

__GFP_NOFAIL 

__GFP_NORETRY 

告诉分配器当满足一个分配有困难时,如何动作。__GFP_REPEAT 表示努力再尝试一次,仍然可能失败;__GFP_NOFAIL告诉分配器尽最大努力来满足要求,始终不返回失败,不推荐使用;__GFP_NORETRY 告知分配器如果无法满足请求,立即返回。 

order:指要释放的物理页数,其取值为2的order次方个。 

返回参数说明

       alloc_pages( )函数返回page结构体指针,指向所分配的物理页中的第一个页,如果分配不成功,则返回NULL。

实例解析

编写测试文件:alloc_page.c

头文件及全局变量声明如下:

 

#include <linux/init.h> 

#include <linux/module.h> 

#include <linux/gfp.h> 

#include <linux/mm_types.h> 

#include <linux/mm.h> 

MODULE_LICENSE("GPL"); 

static int __init alloc_pages_init(void); 

static void __exit alloc_pages_exit(void);  

struct page * pages = NULL;

int __init alloc_pages_init(void) 

       pages = alloc_pages(GFP_KERNEL,3);  //分配8个物理页    

       if(!pages) 

       { 

              return -ENOMEM; 

       } 

       else 

       { 

              printk("<0>alloc_pages Successfully!\n"); 

              printk("<0>pages = 0x%lx\n",(unsigned long)pages);  //输出pages值,即第一个页的页描述符地址

 

        //输出mem_map数组的起始地址

              printk("<0>mem_map = 0x%lx\n",(unsigned long)mem_map); 

 

        //分配的第一个页相对mem_map数组起始位置的偏移

              printk("<0>pages-mem_map = 0x%lx\n",(unsigned long)pages-(unsigned long)mem_map);

 

        //第一个页pages的物理地址

              printk("(pages-mem_map)*4096 = 0x%lx\n",(unsigned long)(pages-mem_map)*4096);

 

        //第一个页pages的逻辑地址

              printk("<0>page_address(pages) = 0x%lx\n",(unsigned long)page_address(pages));

       }     

       return 0; 

}

void __exit alloc_pages_exit(void) 

       if(pages) 

       {

              __free_pages(pages,3);   //释放所分配的8个页 

              printk("<0>__free_pages ok!\n"); 

       }

       printk("<0>exit\n"); 

}

 

module_init(alloc_pages_init); 

module_exit(alloc_pages_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod alloc_pages.ko插入模块,然后执行命令dmesg –c,会出现如图所示的结果:

【转】Linux内存管理内核API函数alloc_pages( ) - 楚江北 - 空谈误己,实干兴业

测试程序中调用了内核函数alloc_pages( )分配2的3次方即8个连续的物理页面,返回指针赋值给pages,指向所分配的物理页中第一个页的结构体。之后通过输出pages相关的一些信息来获取页的分配情况。

首 先输出pages的值,即是第一个页描述符的地址为0xc12c5400。然后输出mem_map数组的起始地址为0xc1000000,它是一个 page类型的数组,管理所有的物理内存,其位置一般是在0xc1000000。(pages-mem_map)是alloc_pages( )函数所分配的第一个页相对mem_map数组起始位置的偏移,由输出信息可知,该偏移值为0x2c5400。(pages-mem_map)*4096 即为页的物理地址(其中4096为每一页面大小),它为0x162a0000。最后调用了宏page_address( ),它接收页的描述符指针作为参数得到该页的逻辑地址,由输出信息可知第一个页pages的逻辑地址为0xd62a0000,它是由该页物理地址 0x162a0000加上PAGE_OFFSET(3G).

具体分析请参考文献:《Linux内核API完全参考手册》邱铁,周玉,邓莹莹 编著,机械工业出版社 2011年1月1日出版
得到的


转载自:http://hi.baidu.com/armlinuxqt/item/2c1f9e049f9106c775cd3c66

<think>好的,我需要解释一下alloc_page和order=0情况下alloc_pages_node函数的作用和机制。首先,用户可能是在学习Linux内核内存管理,尤其是页分配相关的函数。 用户提到了alloc_pagealloc_pages_node在order=0时的情形。我应该先区分这两个函数alloc_page通常是一个宏,可能调用alloc_pages,而alloc_pages_node则是更底层的函数,允许指定节点和标志。 需要明确order=0意味着分配一个物理页(4KB)。这两个函数在这种情况下是否等价?可能alloc_page内部调用了alloc_pages_node,但需要确认参数传递,比如gfp标志和节点选择。 接下来要说明函数原型和参数。例如,alloc_pages_node需要节点ID、gfp_mask和order。当order=0时,就是单页分配。而alloc_page可能隐藏了节点参数,使用当前节点或NUMA_NO_NODE? 需要解释内存分配策略,比如GFP标志的影响,节点的重要性(NUMA架构下),以及可能的失败情况。还要提到可能的封装关系,比如alloc_page可能是alloc_pages的简化版。 还要注意上下文,比如是否可以在中断上下文中调用,GFP_ATOMIC的使用。此外,函数返回的是page结构指针还是其他形式,比如struct page *,这关系到后续如何使用分配的页。 需要确保术语准确,比如“单页”对应的order=0,以及伙伴系统的作用。可能还要比较alloc_pages_node与其他分配函数,比如alloc_pages的区别,是否涉及节点选择。 最后,总结使用场景,帮助用户理解何时选择哪个函数,以及参数设置的注意事项。检查是否有常见的错误用法或需要注意的地方,比如节点选择错误导致性能问题。</think>在Linux内核内存管理中,`alloc_page`和`alloc_pages_node`是用于物理页分配的核心函数。以下从原理和实现角度逐步分析它们在`order=0`(即分配单个物理页)时的行为: --- ### 1. **`alloc_page`函数** - **定义**: ```c #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) ``` 本质是`alloc_pages`的宏封装,固定`order=0`,表示分配$$2^0=1$$个连续物理页(通常4KB)。 - **参数**: - `gfp_mask`:内存分配标志(如`GFP_KERNEL`、`GFP_ATOMIC`),控制分配行为(是否可休眠、内存域等)。 - **返回值**: 成功返回`struct page*`指针,失败返回`NULL`。 - **典型场景**: 需要单个页时使用,如小对象的Slab分配、页缓存等。 --- ### 2. **`alloc_pages_node`函数** - **定义**: ```c struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order); ``` 更底层的接口,允许显式指定NUMA节点。 - **参数解析**: - `nid`:NUMA节点ID。若`nid < 0`(如`NUMA_NO_NODE`),由内核自动选择节点。 - `gfp_mask`:同`alloc_page`,但可能包含`__GFP_THISNODE`强制本地分配。 - `order`:分配阶数。`order=0`时行为与`alloc_page`等价。 - **实现逻辑**: - 检查`nid`有效性,若无效则回退到当前节点。 - 调用`__alloc_pages_node(nid, gfp_mask, order)`进入伙伴系统分配流程。 - 若指定节点内存不足,可能触发回收或跨节点分配(取决于`gfp_mask`)。 - **典型场景**: NUMA优化场景,需显式控制页面的物理位置(如减少远程内存访问)。 --- ### 3. **关键差异对比** | 特性 | `alloc_page` | `alloc_pages_node` (order=0) | |---------------------|----------------------------------|---------------------------------------| | **节点选择** | 自动选择 | 可显式指定NUMA节点 | | **封装层级** | 高层封装(基于`alloc_pages`) | 更底层,直接对接伙伴系统 | | **灵活性** | 简单但限制多 | 更精细控制(节点、内存策略) | --- ### 4. **底层机制** - **伙伴系统(Buddy System)**: 通过维护不同`order`的空闲页块链表,实现快速拆分与合并。`order=0`时直接返回最小单位。 - **NUMA优化**: `alloc_pages_node`通过`nid`参数确保内存本地性,减少跨节点访问延迟。 - **GFP标志影响**: - `GFP_KERNEL`:允许休眠和页面回收,适用于进程上下文。 - `GFP_ATOMIC`:禁止休眠,用于原子上下文(如中断处理)。 --- ### 5. **典型代码路径** ```c // alloc_page调用链 alloc_page(gfp_mask)alloc_pages(gfp_mask, 0)alloc_pages_node(numa_node_id(), gfp_mask, 0) // alloc_pages_node核心逻辑 alloc_pages_node(nid, gfp_mask, order) → if (nid < 0) nid = numa_mem_id(); → __alloc_pages_node(nid, gfp_mask, order) → __alloc_pages(gfp_mask, order, nid, NULL) ``` --- ### 6. **使用建议** - **优先选择**: - 无NUMA需求 → `alloc_page` - 需控制节点 → `alloc_pages_node` - **错误处理**: 必须检查返回值,内核无法容忍未处理的分配失败。 --- **总结**:两者在`order=0`时功能等价,但`alloc_pages_node`提供了NUMA节点的显式控制能力,适合对内存位置敏感的场景。选择时需权衡封装简洁性与控制粒度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值