memblock分配器
系统初始化的时候需要执行一些内存管理 内存分配任务就会需要内存管理器
内核初始化时候memblock分配器
先说说这个memblock分配器 有三个重要的结构体
struct memblock 表示这个分配器 内核初始化的时候 有个全局变量struct memblock
因为一个物理内存(节点node) 划分了不同的区域(zone) 所以这边的分配器根据类型也有个结构体 struct memblock_type
最后用 strcut_memblock_region 描述页的基地址 和大小 和对应的flag
初始化的时候 内核先解析设备树二进制节点 把所有物理内存加载到mem_block这里
在源文件"mm/memblock.c定义全局变量memblock,把成员bottom_ up初始化为假,表示从高地址向下分配。
具体分配的过程在memblock.c 直接一上来就弄了个全局变量在这
看看内核初始化过程
Init/main.c
start_kernel()
set_arch(&command_line)
fdt_ enforce_ memory_ region() ;//解析设备树二进制文件,得到可用内存范围,把超出物理内存的范围找出来,从memblock删除
//全局变量memstart_ addr记录内存的起始物理地址
memstart_ addr = round_ down (memblock_ start_ of_ DRAM() ,ARM64_ MEMSTART_ ALIGN) ;
设备树上的二进制节点 对应的命令行比如 mem内存方位可用内存大小 如果指定了内存大小 把超出长度的物理内存从memblock进行删除 因为内核镜像也被加载到了高地址 并且内核镜像可以通过线性映射区访问 所以要把内核镜像占用物理内存的范围重新添加
memblock分配器 源码查看
struct memblock {bool bottom up; // 表示分配内存的方式,值为真表示从低地址向上分配,值为假表示从高地址向下分配phys_ addr_ t current_ limit; //可分配内存的最大物理地址struct memblock_ type memory; //内存类型(包括已分配的内存和未分配的内存)struct memblock_ type reserved; //预留类型(已分配的内存)#ifdef CONFIG_ HAVE_ MEMBLOCK_ PHYS_ MAPstruct memblock_ type physmem; //物理 内存类型,#endif
};
物理内存类型和内存类型区别:内存类型是物理内存类型的子集,在引导内核时可以使用内核参数"mem= nn[KMG]“,指定可用内存的大小,导致内核不能看见所有的内存;物理内在类型总是包含所有内存范围,内存类型只包含内核参数” mem="指定的可用内在范围。
结构体 memblock_ _type
struct memblock_ _type {
unsigned long cnt;
// 当前管理集合中记录的内存区域个数
unsigned long max;
//当前管理集合中记录的内存区域的最大个数,最大值是INIT_ PHYSMEM REGIONS
phys_ _addr_ _t total_ size; //所有内存块区域的总长度
struct memblock_ region *regions; //执行内存区域结构的指针
char *name; //内存块类型的名称
};
//内存块区域的数据结构
struct memblock_ region {
phys_ _addr_ _t base; //起始物理地址
phys_ _addr_ _t size; //长度
unsigned long flags; //成员falgs是标志
#i fdef CONFIG HAVE MEMBLOCK NODE MAP
int nid; //节点编号
#endi f
};
// memblock分配器标志位定义
enum {//表示没有特殊要求区域MEMBLOCK_ NONE= 0x0, /* No special request *///表示可以热插拔的区域,即在系统运行过程中可以拔出或插入物理内存MEMBLOCK_ HOTPLUG= 081, /* hotpluggable region *///表示镜像的区域。将内存数据做两个复制,分配放在在主内存和镜像内存中MEMBLOCK_ MIRROR= 0x2,/* mirrored region *///表示不添加到内核直接映射区域(即线性映射区域)MEMBLOCK_ NOMAP= 0x4, /* don't add to kernel direct mapping */
};
伙伴分配器
术语扫盲
虚拟地址
cpu看见的: 虚拟ram内存地址 需要mmu把(物理ram+外围设备)内存地址进行映射给cpu看
ram物理地址
外围设备和物理ram内存使用统一 的物理地址空间
之前有个图又放来这边用用
RAM中表示物理ram的一些结构体-
页:struct page ,如下图所示,x86架构下一般为4K为大小
分区:struct zone ,把整个内存划分为不同区域,x86架构下分为三个区 ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM+
子结构体 struct free_area 区中空闲的区域
本文重点在分区
内存节点:struct node。对于一个简单的嵌入式系统只有一个node,
ZONE_DMA,一般由于内存碎片,有可能申请不到连续的一片物理内存,而DMA需要连续的物理内存,所以在X86下给DMA大概会留一块连续的16M的物理内存。
背景描述
伙伴分配器用在ram的物理内存管理 为什么有ram内存管理
长时间使用会有内存碎片化 引入内存管理系统
物理内存被分为几个区域。每一个区域都有一个伙伴系统。每个伙伴系统都管理着每个zone的物理内存。但是他们的原理一样。
介绍
伙伴系统(Buddy System)是一种管理物理内存的算法,主要于管理大块的内存区域,如页框。
伙伴系统通过将大的内存块不断分割成两个较小的伙伴块,然后按照块大小将伙伴块归入不同的空闲链表中,以便快速找到符合要求的内存块。
伙伴系统通常用于分配物理内存,由于内核中的物理内存总量比较有限,因此在分配物理内存时需要考虑内存碎片的问题。
而slab则是用于管理内核对象的内存分配器。
它的设计目的是为了提高内核对象的内存分配效率,减少内存碎片,提高内存分配的速度。slab分配器将内存分为不同的slab,每个slab管理一 类内核对象,slab中的页框可以被分配给该类对象进行使用,从而提高了内存的利用率和访问速度。
在实现上,伙伴系统和slab通常是一起使用的。当需要为内核对象分配内存时,slab会先从伙伴系统中分配出一块合适大小的物理内存,然后将该物理内存划分为slab,并在其中管理内核对象。因此,伙伴系统和slab可以说是相互配合的内存管理机制。
zone区域结构体查看
看的是zone结构体 表示物理ram区域的结构体 因为伙伴系统需要的属性都保存在zone结构体里。
zone结构体是描述物理内存区域的数据结构,所以能理解为每个zone都有一个自己的伙伴分配器
其中包含了伙伴系统需要的所有属性。下面是 zone中伙伴系统需要使用到的属性:
struct zone {unsigned long watermark[NR_WMARK];//伙伴系统需要使用水位线来控制内存的分配和回收,其中//watermark表示内存空闲的水位线,watermark boost表示需要提高的水位线。long lowmem_reserve[MAX_NR_ZONES];unsigned long zone_start_pfn;//表示该区域的起始页框号。unsigned long managed_pages;//表示该区域管理的页框总数,包括已分配和未分配的页框。unsigned long spanned_pages;//示该区域所管理的所有物理页框的数量。unsigned long present_pages;//struct free_area free_area[MAX_ORDER]; //伙伴系统需要在每个区域内维护可用内存块的链表,这些链表就存储在free _area数组中。unsigned long flags;//存储了该区域的一些状态信息,例如该区域是否允许交换、是否允许内存高端地址分配等。...
} ____cacheline_internodealigned_in_smp;
该区域空闲的位置 zone->free_area,简单说一下内存足够的时候怎么分配的
struct free_area {struct list_head free_list[MIGRATE_TYPES];unsigned long nr_free;
};
结构体free_ area 是伙伴系统中管理每个块大小的可用空闲页框链表的数据结构。它定义了一个数组free_ list, 每个元素都是一个链表头, 代表了一个特定大小的空闲页框的链表。
nr_ free记录了该数组中链表中可用的空闲页框数量。nr_ free记录的是free_ list数组中存储的空闲页的数量。因为每个空闲块都对应一个空闲页,所以nr_ free等于所有free_ list数组中链表节点个数之和。free_ area 是作为一个zone结构体中的一部分来使用的。
zone是Linux内核中的一个管理物理内存的单元,一个物理内存可以被划分为多个zone,每个zone中包含了一定数量的物理页框。
在一个zone中,free_ area 数组中的每个元素都代表了该zone中的一一个固定大小的页框。
zone中的页框大小按照2的幂次方增加,即从小到大排列,如free_ area[0] 示一个页框大小为2^0个物理页框的链表,
free_ area[1] 示-个页框大小为2^1个物理页框的链表,
依此类推,直到最大的页框大小2^{MAX_ ORDER}。
在伙伴系统中,每个可用的空闲页框都被划分到适当大小的free_ area 链表中。
例如,当系统需要一个大小为2^3个物理页框的连续空间时,会在free_ area[3] 的链表中查找。
如果free_ area[3]中没有可用的空闲页框,系统会向较大的链表free_ area[4] 甚至更大的链表中寻找可用空闲页框。
如果所有的free_ area链表中都没有可用的空闲页框,那么系统就需要等待一段时间,直到有足够数量的页框空闲为止。
在释放一个空闲页框时,它会被添加到对应的free_ area链表中,等待被再次分配。
通过这种方式,伙伴系统可以高效地管理可用的空闲页框,同时避免了内存碎片化的问题。
free_ area中free_ list链表下一个结点对应的就是page中的buddy_ list,
再通过计算地址即可得到需要的page,后续的笔记会记录Linux的数据机构。
内存不足怎么分配物理页到这个区域
当前这个物理区域会根据水位线(下面会说)来判断当前区域的内存是否足够
内存不足的话会考虑去备用区域寻找页 进行分配
先看看内存节点结构体
struct page
{//节点结构体里面还有个数据结构体来表示它的zonetypedef struct pglist_ data {struct zone node_ zones [MAX_ NR_ ZONES]; //内存区域数组struct zonelist node_ zonelists[MAX_ ZONELISTS]; //备用区域列表int nr_ _zones; //该节点包含的内存区域数量}
};
备用区域
两个借用规则 如果能满足当前zone的借用规则 就被放到了这个zone的备用区域列表中
借用必须遵守规则: 节点规则(嵌入式可以不关心 我们就一个节点)
一个内存节点的某个区域类型可以从另-一个内存节点的相同区域类型借用物理页,比如节点0的普通区
域可以从节点1的普通区域借用物理页;
借用必须遵守规则: 高低区域规则
高区域类型可以从低区域类型借用物理页,比如普通区域可以从DMA区域借用物理页; .
低区域类型不能从高区域类型借用物理页。比如DMA区域不能从普通区域借用物理页。
水位线
上面的区域结构体中 有个数组变量来表示水位线
首选的内存区域什么情况下从备用区域借用物理页呢?每个内存区域有3个水线
a.高水线(high) :如果内存区域的空闲页数大于高水线,说明内存区域的内存充足;
b.低水线(low) :如果内存区域的空闲页数小于低水线,说明内存区域的内存轻微不足;
C.最低水线(min) : 如果内存区域的空闲页数小于最低水线,说明廖内存区域的内存严重不足。
最后看看怎么分配的流程和系统中如何查看
第一次尝试使用低水线 如果首选内存区域的空闲页的数量小于低水线 就从备用区域借用物理页 如果还是失败 就换起所有内存节点的页回收线程 用异步的方式进行回收页 再一次尝试最低水线
如下能看到每个节点 对应的每个区域 里面分别的水线
han@ubuntu:~$ cat /proc/zoneinfo
Node 0, zone DMAper-node statsnr_inactive_anon 10820nr_active_anon 320858nr_inactive_file 231022nr_active_file 234555nr_unevictable 16nr_slab_reclaimable 44884nr_slab_unreclaimable 18674nr_isolated_anon 0nr_isolated_file 0workingset_nodes 0workingset_refault 0workingset_activate 0workingset_restore 0workingset_nodereclaim 0nr_anon_pages 320578nr_mapped 153680nr_file_pages 476705nr_dirty 26878nr_writeback 0nr_writeback_temp 0nr_shmem 11129nr_shmem_hugepages 0nr_shmem_pmdmapped 0nr_file_hugepages 0nr_file_pmdmapped 0nr_anon_transparent_hugepages 0nr_unstable 0nr_vmscan_write 0nr_vmscan_immediate_reclaim 0nr_dirtied 287542nr_written 244390nr_kernel_misc_reclaimable 0pages free 3968min 77low 96high 115spanned 4095present 3997managed 3976protection: (0, 2445, 3369, 3369, 3369)nr_free_pages 3968nr_zone_inactive_anon 0nr_zone_active_anon 0nr_zone_inactive_file 0nr_zone_active_file 0nr_zone_unevictable 0nr_zone_write_pending 0nr_mlock 0nr_page_table_pages 0nr_kernel_stack 0nr_bounce 0nr_zspages 0nr_free_cma 0numa_hit 1numa_miss 0numa_foreign 0numa_interleave 0numa_local 1numa_other 0pagesetscpu: 0count: 0high: 0batch: 1vm stats threshold: 6cpu: 1count: 0high: 0batch: 1vm stats threshold: 6cpu: 2count: 0high: 0batch: 1vm stats threshold: 6cpu: 3count: 0high: 0batch: 1vm stats threshold: 6node_unreclaimable: 0start_pfn: 1
Node 0, zone DMA32pages free 43834min 12202low 15252high 18302spanned 1044480present 782288managed 759709protection: (0, 0, 924, 924, 924)nr_free_pages 43834nr_zone_inactive_anon 8454nr_zone_active_anon 245858nr_zone_inactive_file 181846nr_zone_active_file 177532nr_zone_unevictable 4nr_zone_write_pending 26534nr_mlock 4nr_page_table_pages 5641nr_kernel_stack 8472nr_bounce 0nr_zspages 0nr_free_cma 0numa_hit 4159869numa_miss 0numa_foreign 0numa_interleave 192366numa_local 4159869numa_other 0pagesetscpu: 0count: 50high: 378batch: 63vm stats threshold: 36cpu: 1count: 335high: 378batch: 63vm stats threshold: 36cpu: 2count: 300high: 378batch: 63vm stats threshold: 36cpu: 3count: 121high: 378batch: 63vm stats threshold: 36node_unreclaimable: 0start_pfn: 4096
Node 0, zone Normalpages free 5754min 4615low 5768high 6921spanned 262144present 262144managed 236760protection: (0, 0, 0, 0, 0)nr_free_pages 5754nr_zone_inactive_anon 2366nr_zone_active_anon 75000nr_zone_inactive_file 49176nr_zone_active_file 57023nr_zone_unevictable 12nr_zone_write_pending 344nr_mlock 12nr_page_table_pages 5556nr_kernel_stack 7096nr_bounce 0nr_zspages 0nr_free_cma 0numa_hit 839519numa_miss 0numa_foreign 0numa_interleave 223408numa_local 839519numa_other 0pagesetscpu: 0count: 253high: 378batch: 63vm stats threshold: 24cpu: 1count: 202high: 378batch: 63vm stats threshold: 24cpu: 2count: 325high: 378batch: 63vm stats threshold: 24cpu: 3count: 291high: 378batch: 63vm stats threshold: 24node_unreclaimable: 0start_pfn: 1048576
Node 0, zone Movablepages free 0min 0low 0high 0spanned 0present 0managed 0protection: (0, 0, 0, 0, 0)
Node 0, zone Devicepages free 0min 0low 0high 0spanned 0present 0managed 0protection: (0, 0, 0, 0, 0)
han@ubuntu:~$