伙伴系统分配内存的接口(include/gfp.h)
具体函数如下:
struct page *alloc_pages(gfp_t gfp, unsigned int order);
#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask), 0)
extern void __free_pages(struct page *page, unsigned int order);
extern void free_pages(unsigned long addr, unsigned int order);
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)
struct page *alloc_pages(gfp_t gfp, unsigned int order);
gfp:
这些函数用于动态请求指针对齐的内存块,类似用户空间中的malloc和free,但
:c:func:kmalloc()
需要额外的标志词。重要的值:
GFP_KERNEL
可以睡眠和交换以释放内存。只允许在用户上下文中使用,但这是分配内存最可靠
的方法。
GFP_ATOMIC
不会睡眠。较 GFP_KERNEL
更不可靠,但可以从中断上下文调用。你 应该
有一个很好的内存不足错误处理策略。
GFP_DMA
分配低于16MB的ISA DMA。如果你不知道那是什么,那你就不需要了。非常不可靠。
如果您看到一个从无效上下文警告消息调用的睡眠的函数,那么您可能在没有
GFP_ATOMIC
的情况下从中断上下文调用了一个睡眠的分配函数。你必须立即修复,快点!
order: 0到MAX_ORDER-1,0代表4K ,1代表 8K,2代表2的2次方式4*4K 16K,以此类推
通过申请内存的接口从伙伴系统(4K-4M空间的内存分配)中空闲的内存块上取出合适的内存,返回给用户使用。
mmzone.h
代码示例
#include
#include
#include
#include
MODULE_LICENSE("GPL");
struct page * page;
unsigned long int vir_adr;
static int init_hello(void)
{
page = alloc_pages(GFP_KERNEL,1);
printk("page frame no: %lx n",page_to_pfn(page));
printk("physical addr: %x n",page_to_phys(page));
printk("virtual addr: %lx n",(unsigned int)page_address(page));
vir_adr = (unsigned long)page_to_virt(page);
printk("virtual addr: %lx n",vir_adr);
printk("init hellon");
return 0;
}
static void exit_hello(void)
{
free_pages(vir_adr,1);
printk("exit hellon");
}
module_init(init_hello);
module_exit(exit_hello);
代码运行结果
- 注意事项:
void free_pages(unsigned long addr, unsigned int order);中addr代表的是虚拟地址,不是物理地址
Q&A
问题:分配的内存必须给用户空间使用吗?
答案:不正确,伙伴系统是对用户的内存空间进行管理的。但用户空间内存,内核空间也是可以使用的。
问题:伙伴系统管理的内存范围是多少?
答案:ZONE_DMA 管理16M内存,大部分的内存都是由ZONE_NORMAL空间进行管理的。在arm系统中是没有ZONE_DMA空间的。伙伴系统管理着系统中大部分的内存,无法确定具体大小。比如struct page的内存我推测不是由伙伴系统管理的,具体细节现在我也不清楚,还有per_cup页帧缓存本分的内存也不是伙伴系统管理的,这个在操作系统的使用过程中会进行动态分配和回收
问题:page_address(page)和page_to_virt(page)的区别是什么?
答案:还不清楚
问题:alloc_pages是如何申请内存的
答案:如果申请的是4K先从pre_cup(每个CPU自己的列表中获取),如果没有再从伙伴系统中获取,如果无法申请到则对内存进行整理后在进行申请
Linux代码基于:linux-6.5.2
代码运行结果基于:linux-headers-5.4.0-100-generic(Ununtu)