关于内核vmalloc中vmap_area与vm_struct双结构体的疑问
为什么Linux内核用vmap_area和vm_struct两个结构体而非合并?
先贴出相关内核结构体代码:
struct vm_struct { struct vm_struct *next; void *addr; unsigned long size; unsigned long flags; struct page **pages; #ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC unsigned int page_order; #endif unsigned int nr_pages; phys_addr_t phys_addr; const void *caller; }; struct vmap_area { unsigned long va_start; unsigned long va_end; struct rb_node rb_node; /* address sorted rbtree */ struct list_head list; /* address sorted list */ /* * The following two variables can be packed, because * a vmap_area object can be either: * 1) in "free" tree (root is vmap_area_root) * 2) or "busy" tree (root is free_vmap_area_root) */ union { unsigned long subtree_max_size; /* in "free" tree */ struct vm_struct *vm; /* in "busy" tree */ }; };
核心原因拆解:
职责分离,降低耦合
vm_struct专注描述已分配vmap内存块的核心属性:比如对应的物理页数组、内存大小、申请标记、调用者信息等,完全和具体内存资源绑定。而vmap_area只负责虚拟地址空间的管理:记录地址范围、维护红黑树/链表节点实现高效的地址查找、分配、释放,还通过union区分空闲/忙状态。
拆分后,虚拟地址管理逻辑和内存块资源管理逻辑完全解耦——优化地址分配算法时只需改动vmap_area相关代码,调整内存块属性时也不会影响地址管理,维护成本大幅降低。优化内存开销,适配两种状态
vmap_area里的union是关键设计:当它代表空闲虚拟地址块时,仅需subtree_max_size辅助红黑树高效查找;当转为已分配状态时,才关联对应的vm_struct。如果合并结构体,空闲地址块也得带着vm_struct里的pages、nr_pages等无用字段,这对内存紧张的内核来说是没必要的浪费——系统中可能存在大量空闲地址块,轻量的vmap_area能节省不少内存。历史演进与稳定性优先
早期内核只有vm_struct管理vmap内存,后来随着虚拟地址空间需求复杂化(比如支持更大地址范围、更高效分配释放),才新增vmap_area专门负责地址管理。强行合并需要修改大量依赖vm_struct的旧代码,不仅工作量极大,还容易引入兼容性问题和bug。内核作为稳定性优先的基础软件,不会轻易做这种破坏性重构,而是选择新增结构扩展功能,保留原有结构的兼容性。
内容的提问来源于stack exchange,提问作者Jianhui Zhao
相关产品推荐
相关产品推荐

