引子:
工作中遇到这样的问题,调用alloc_pages(GFP_KERNEL, 13),返回值为NULL,并且打印告警。使用cat /proc/buddyinfo 命令查看,最大为2的10次方,将13改为10,函数成功调用。
引.1 alloc_pages函数
alloc_pages
是 Linux 内核中用于分配物理内存页面的函数。它通常用于内核模块、驱动程序等需要直接访问物理内存的场景。alloc_pages
函数可以分配一个或多个连续的物理页面,并且分配的页面个数只能是2的整数次幂。在Linux 中,内存管理是非常核心和复杂的一部分,其中 alloc_pages
函数处于内核内存管理的最底层。无论slab、vmalloc、kmalloc、mmap、brk 还是 page cache、buffer,都需要通过 alloc_pages
获取最基本的物理内存 pages。
函数原型如下:
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order);
参数解释:
gfp_mask:这是一个标志掩码,用于指定内存分配的策略和行为。不同的 gfp_mask 值表示不同的内存分配类型,例如:是否可以睡眠、是否需要回收页面、是否允许从高端内存区域分配等。
order:这是一个无符号整数,表示要分配的物理页面的数量。例如,order 为3表示分配2^3=8个连续的物理页面,一般一个页的大小为4kB,所以order为3时表示分配32kB的内存。
返回值
如果成功,alloc_pages 返回一个指向分配的第一个 struct page 的指针。如果失败,返回 NULL。
函数功能
alloc_pages 的主要功能是从物理内存中分配指定数量的连续页面。这些页面可用于各种目的,例如缓冲区、缓存、映射等。
page_address
是 Linux 内核中的一个宏,用于获取物理页面的逻辑地址。在 Linux 中,物理内存页面是通过 page 结构体来表示的,而 page_address
宏的作用就是将一个指向 page 结构体的指针转换为该页面的逻辑地址,这个逻辑地址是该页面的虚拟地址,可以用于访问和操作该页面。
引.2 /proc/buddyinfo文件
/proc/buddyinfo
是 Linux 内核中 Buddy 算法的输出文件,用于显示内存空闲和分配情况,帮助管理员和开发者更好地了解和管理系统的内存资源。
cat buddyinfo结果示例:
[root@100ask:/proc]# cat buddyinfo
Node 0, zone Normal 13 9 4 4 3 5 3 1 3 3 3 3 1 8
Node 0: 表示这是第一个NUMA节点。如果你的系统有多个处理器和内存节点,那么每个节点都会有一个对应的条目。
zone Normal: 表示这是Normal内存区域,这是最常见的内存区域类型,用于普通的页面分配。
接下来的数字代表了从Order 0到Order 15的空闲页面块的数量。在这个例子中,数字分别对应:
Order 0: 13
Order 1: 9
Order 2: 4
Order 3: 4
Order 4: 3
Order 5: 5
Order 6: 3
Order 7: 1
Order 8: 3
Order 9: 3
Order 10: 3
Order 11: 3
Order 12: 1
Order 13: 8
(注意:Order 14 和 Order 15 的数量没有显示,通常这意味着它们的值为0。)
这些数字表明系统中有多少连续的内存页面块是空闲的,并且可以被用来满足相应大小的内存分配请求。例如,Order 0有13个空闲页面块,每个块包含一个页面;Order 1有9个空闲块,每个块包含两个页面,依此类推。
分析这些数字可以帮助你了解系统的内存使用情况和潜在的碎片问题。如果高阶的块数量很少,而低阶的块数量很多,这可能意味着存在内存碎片。这是因为大型的内存分配请求可能需要高阶的连续内存块,而这些块可能由于碎片而不可用。
引.3 为什么要分配连续的物理页
DMA需要使用连续物理内存。
1.内存管理相关知识目录
2.内存的硬件电路与接口
计算机最小系统至少包含内存+机械硬盘(flash),内存读写速度快但是断电丢失,机械硬盘读写速度慢但是断电不丢失。
控制器将CPU发出来的地址信号转换为控制DDR的读写信号,所以设备上电后的一个重要工作的就是初始化DDR控制器。
一般CPU中会集成一块SRAM,程序先从flash中加载到SRAM中去执行,在SARM中执行的程序中会初始化DDR控制器,然后再把程序拷贝到DDR中去执行。
广义内存泄漏:多次在DDR中申请内存,导致内存中没有连续的内存空间,再次申请连续内存时失败,即内存碎片化。
狭义内存泄漏:申请内存后,没有释放。
3.物理内存管理page,zone和node
为了避免内存碎片,linux会对物理内存进