Linux v6.0中alloc_pages_node未递增所有分配页的_refcount问题咨询
关于Linux v6.0中alloc_pages_node分配内存时struct page _refcount的疑问解答
问题背景
在Linux v6.0中使用alloc_pages_node分配物理连续内存时,仅分配区域首页的struct page中的_refcount被递增为1,其余页的_refcount均为0。相关代码及输出如下:
运行代码
order = get_order(nr_pages << PAGE_SIZE); p = alloc_pages_node(node, gfp_mask, order); if (!p) return; for(i = 0; i < nr_pages; i++, p++) printk("_refcount = %d", p->_refcount);
输出结果
_refcount = 1 _refcount = 0 _refcount = 0 ...
参数说明
gfp_mask为(THREADINFO_GFP & ~__GFP_ACCOUNT) | __GFP_NOWARN | __GFP_HIGHMEM,其中THREADINFO_GFP & ~__GFP_ACCOUNT由alloc_thread_stack_node传入,__GFP_NOWARN | __GFP_HIGHMEM由__vmalloc_area_node添加;nr_pages为4,因此order = get_order(nr_pages << PAGE_SIZE) = 2。
用户咨询两个问题:
- 这是否为正确/预期行为?
- 该函数是否仅适用于特定场景,从而无需关注非首页的
_refcount?
解答
1. 属于预期行为
伙伴分配器处理连续页分配时,仅会对分配区域的首页设置_refcount为1,其余页的_refcount保持初始值0,这是内核的设计逻辑:
- 连续页分配是以"页块"为单位管理的,首页作为整个块的代表,其引用计数负责跟踪整个块的使用状态;
- 非首页的
struct page在连续分配场景下不会被单独引用或释放,因此不需要维护独立的引用计数。
而vmalloc这类非连续分配API分配的是离散页,每个页都需要独立跟踪引用状态,所以会递增所有页的_refcount,这和伙伴分配器的连续页管理逻辑完全不同。
2. 函数适用场景与引用计数关注点
alloc_pages*系列函数适用于需要物理连续内存的场景,比如:
- 内核早期启动阶段的栈分配(如你提到的init进程和kthreadd栈设置);
- 设备驱动中需要直接访问物理连续地址的硬件缓冲区;
- 高性能内存分配场景,避免TLB miss带来的性能损耗。
在这些场景下,开发者只需关注首页的_refcount:
- 释放时使用
__free_pages或对应释放函数,传入首页指针和分配时的order,内核会自动处理整个连续页块的释放,无需操作非首页的引用计数; - 非首页的
struct page不会被单独操作,其_refcount为0是正常状态,不影响内存的管理和使用。
内容的提问来源于stack exchange,提问作者TSG
相关产品推荐
相关产品推荐

