浅学内存分配与释放(二)

物理内存中的伙伴

虚拟内存分配是以内存块为单位,但是,物理内存被划分成一个一个大小一致的物理页(4kb), 所以,物理内存分配是以 "物理页" 为单位

Linux操作系统同样使用"分离空闲链表"数据结构,来搞物理内存的分配与释放。

从上图我们看到:(你要注意的是,这里后边画的是三个三个的,其实后边有很多很多哈,只不过是没画出来了而已......)

第0阶中------都是------1个物理页------串起来

第1阶中------都是------2个物理页------串起来

第2阶中------都是------4个物理页------串起来

第3阶中------都是------8个物理页------串起来

伙伴

你要注意的是,这里后边画的是三个三个的,其实后边有很多很多哈,我就不画出来了

指定阶(order)、指定物理页号,通过计算,很快能得到只当物理页的伙伴是谁

使用伙伴算法模拟物理页分配

(1)剩余的部分插入到第2阶中(小伙伴分开了) (2)剩余的部分递归分割插入到第1阶中(小伙伴分开了) 物理内存对NUMA架构和稀疏内存模型(64位操作系统)中的再次细化展示 区域:(Zone): 不同区域的内存有不同的用途,便于管理。

分区名称 适用架构 物理地址范围(典型值) 内核虚拟地址映射方式 主要用途 / 使用限制 伙伴系统水线标记 常见标志位
ZONE_DMA 32 位 x86 / 部分嵌入式 0 ~ 16 MiB 线性映射(直接映射区) 兼容早期 ISA 设备,只能访问低 16 MiB;DMA 掩码 24 bit min/low/high + DMA 水线 GFP_DMA
ZONE_DMA32 64 位 x86_64 / arm64 0 ~ 4 GiB(x86_64 为 0-1 GiB) 线性映射 给 32 位 DMA 设备(AHCI USB3 NIC 等)提供内存,掩码 32 bit min/low/high + DMA32 水线 GFP_DMA32
ZONE_NORMAL 32/64 通用 16 MiB ~ 896 MiB(32 位) 1 GiB ~ 64 GiB(64 位,与 DRAM 大小有关) 线性映射(永久映射) 内核直接访问的"普通"页,绝大多数 slab、kmalloc、进程匿名页 标准水线 0(默认)
ZONE_HIGHMEM 仅 32 位 x86 896 MiB ~ 最大物理内存 动态映射(kmap/highmem 映射) 用户进程页缓存、匿名页;内核需临时映射才能访问 高水线更早触发回收 GFP_HIGHUSER
ZONE_MOVABLE 任意架构 人为划定区域,与上述分区重叠 线性映射 供可迁移页使用,防止内存碎片;可热插拔内存主要落在此区 无水线,仅作迁移目标 __GFP_MOVABLE
ZONE_DEVICE 任意架构 任意地址(通过 HMM / PCIe BAR) 设备 MMIO 映射 持久内存(PMEM)、GPU 显存、RDMA 网卡内存,支持 DMA-buf / P2P 无水线,由驱动自行管理 GFP_TRANSHUGE_LIGHT

伙伴系统(算法)对外提供的物理内存分配或释放API

gfp: 表示希望在哪个区域分配内存

  1. GFP_USER 用于分配一个页 映射 到用户进程的虚拟地址空间,并且希望直接被内核或硬件访问,主要用于一个用户进程希望通过内存映射的方式,访问某些硬件的缓存,例如显卡缓存
  2. GFP_KERNEL 用于内核中分配页,主要分配ZONE_NORMAL区域,也就是直接映射区
  3. GFP_HIGHMEM 顾名思义就是主要分配高端区域的内存

order: 表示分配2的order次方个页

内核态下虚拟内存的分配

Slab分配器

功能:为内核程序分配小对象内存,降低内部内存碎片的产生 通用:将连续页帧划分成通用大小的小块(比如:8字节) 专用:按照指定对象大小来划分

Slab分配器中的数据结构

slab :(石、木等硬质材料的)厚板;(蛋糕、面包、巧克力等的)厚块;(烹饪食品时所用的)厚桌面,砧板;

一个slab中包含了若干个物理页帧(这些连续的物理页帧是分配器一次性从伙伴系统申请过来的噢!它们就组成了一个slab)

存储相同大小的多个slab,由数据结构kmem_cache 来管理 A. 通用的名字

kmalloc-8, 里面每个小块都是8字节,你的对象申请小于等于8,分配器都从这里给你。

kmalloc-32, 里面每个小块都是32字节,你的对象申请小于等于32,分配器都从这里给你。

B. 专用的名字

如:vm_area_struct , 每个小块都是存vm_area_struct对象的,216个字节

再次细化展示一下kmem_cache结构体中的内容:

kmem_cache中的变量数据结构体,只列举了部分结构体,更详细的请AI或查看源码

✅ 1. kmem_cache_node[NUM_NODES] 这是 每个内存节点(NUMA node) 的缓存信息数组。

  • 作用:在 NUMA 架构下,每个节点(node)有自己的内存,Linux 的 slab 分配器会为每个节点维护一个

kmem_cache_node 结构,用于管理该节点上的 slab 缓存。

✅ 2. array_cache_percpu 这是 每 CPU 的缓存数组,用于 减少锁竞争。

  • 作用:每个 CPU 都有一个本地的对象缓存(array cache),用于快速分配和释放对象,避免频繁访问全局的 slab 链表。

内核的内存分配

内核中的程序可以通过kmalloc分配连续的物理页帧

内核中的程序可以通过vmalloc分配非连续的物理页帧

特性 kmalloc vmalloc
分配内存类型 物理连续,虚拟也连续 仅虚拟连续,物理不连续
最大单块大小 通常 ≤ 128 KB(受限于连续物理页) 仅受限于内核虚拟地址空间(可 MB/GB 级)
释放函数 kfree() vfree()
物理地址 可获取,满足 DMA 需求 物理地址不连续,不可用于 DMA
相关推荐
dessler3 小时前
Hadoop HDFS-认证(Kerberos) 部署与配置
linux·运维·hdfs
360智汇云3 小时前
k8s共享存储fuse-client三种运行方案对比
java·linux·开发语言
Mr.45674 小时前
Linux&Windows环境下Nacos3.1.0详细安装配置指南:从零到生产就绪
linux·运维·服务器
峰顶听歌的鲸鱼5 小时前
30.Linux DHCP 服务器
linux·运维·服务器·笔记·学习方法
Lzc7745 小时前
Linux的网络基础
linux·linux的网络基础
violet-lz5 小时前
Linux文件系统调用:文件调用函数与exec系统函数详解与应用
linux·运维·服务器
袁泽斌的学习记录7 小时前
ubuntu22.04安装cuda11.4版本
linux·运维·服务器
用户31187945592187 小时前
CentOS 7 安装 net-tools.rpm 包步骤详解(附 rpm 命令和 yum 方法)附安装包
linux