linux kernel组织管理物理内存的方式是buddy system(伙伴系统),而物理内存碎片正式buddy system的弱点之一,为了预防以及解决碎片问题,kernel采取了一些实用技术,这里将对这些技术进行总结归纳。
1低内存时整合碎片
从buddy申请内存页,如果找不到合适的页,则会进行两步调整内存的工作,compact和reclaim。前者是为了整合碎片,以得到更大的连续内存;后者是回收不一定必须占用内存的缓冲内存。这里重点了解comact,整个流程大致如下:
__alloc_pages_nodemask
-> __alloc_pages_slowpath
-> __alloc_pages_direct_compact
-> try_to_compact_pages
-> compact_zone_order
-> compact_zone
-> isolate_migratepages
-> migrate_pages
-> release_freepages
并不是所有申请不到内存的场景都会compact,首先要满足order大于0,并且gfp_mask携带__gfp_fs和__gfp_io;另外,需要zone的剩余内存情况满足一定条件,kernel称之为“碎片指数”(fragmentation index),这个值在0~1000之间,默认碎片指数大于500时才能进行compact,可以通过proc文件extfrag_threshold来调整这个默认值。fragmentation index通过fragmentation_index函数来计算:
/*
* index is between 0 and 1000
*
* 0 => allocation would fail due to lack of memory
* 1000 => allocation would fail due to fragmentation
*/
return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ull, requested))), info->free_blocks_total)
在整合内存碎片的过程中,碎片页只会在本zone的内部移动,将位于zone低地址的页尽量移到zone的末端。申请新的页面位置通过compaction_alloc函数实现。
移动过程又分为同步和异步,内存申请失败后第一次compact将会使用异步,后续reclaim之后将会使用同步。同步过程只移动当面未被使用的页,异步过程将遍历并等待所有movable的页使用完成后进行移动。
2按可移动性组织页
按照可移动性将内存页分为以下三个类型:
unmovable:在内存中位置固定,不能随意移动。kernel分配的内存基本属于这个类型;
reclaimable:不能移动,但可以删除回收。例如文件映射内存;
movable:可以随意移动,用户空间的内存基本属于这个类型。
申请内存时,根据可移动性,首先在指定类型的空闲页中申请内存,每个zone的空闲内存组织方式如下:
struct zone {
......
struct free_area free_area[max_order];
......
}
struct free_area {
struct list_head free_list[migrate_types];
unsigned long nr_free;
};
当在指定类型的free_area申请不到内存时,可以从备用类型挪用,挪用之后的内存就会释放到新指定的类型列表中,kernel把这个过程称为“盗用”。
备用类型优先级列表如下定义:
static int fallbacks[migrate_types][4] = {
[migrate_unmovable] = { migrate_reclaimable, migrate_movable, migrate_reserve },
[migrate_reclaimable] = { migrate_unmovable, migrate_movable, migrate_reserve },
#ifdef config_cma
[migrate_movable] = { migrate_cma, migrate_reclaimable, migrate_unmovable, migrate_reserve },
[migrate_cma] = { migrate_reserve }, /* never used */
#else
[migrate_movable] = { migrate_reclaimable, migrate_unmovable, migrate_reserve },
#endif
[migrate_reserve] = { migrate_reserve }, /* never used */
#ifdef config_memory_isolation
[migrate_isolate] = { migrate_reserve }, /* never used */
#endif
};
值得注意的是并不是所有场景都适合按可移动性组织页,当内存大小不足以分配到各种类型时,就不适合启用可移动性。有个全局变量来表示是否启用,在内存初始化时设置:
void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
{
......
if (vm_total_pages < (pageblock_nr_pages * migrate_types))
page_group_by_mobility_disabled = 1;
else
page_group_by_mobility_disabled = 0;
......
}
如果page_group_by_mobility_disabled,则所有内存都是不可移动的。
其中有个参数决定了每个内存区域至少拥有的页,pageblock_nr_pages,它的定义如下:
#define pageblock_order hugetlb_page_order
#else /* config_hugetlb_page */
/* if huge pages are not used, group by max_order_nr_pages */
#define pageblock_order (max_order-1)
#endif /* config_hugetlb_page */
#define pageblock_nr_pages (1ul
&& (pfn = order;
--current_order) {
for (i = 0;; i++) {
migratetype = fallbacks[start_migratetype][i];
......
}
可以通过/proc/pageteypeinfo查看当前系统各种类型的页分布。
3虚拟可移动内存域
在依据可移动性组织页的技术之前,还有一个方法已经合入kernel,那就是虚拟内存域:zone_movable。基本思想很简单:把内存分为两部分,可移动的和不可移动的。
enum zone_type {
#ifdef config_zone_dma
zone_dma,
#endif
#ifdef config_zone_dma32
zone_dma32,
#endif
zone_normal,
#ifdef config_highmem
zone_highmem,
#endif
zone_movable,
__max_nr_zones
};
zone_movable的启用需要指定kernel参数kernelcore或者movablecore,kernelcore用来指定不可移动的内存数量,movablecore指定可移动的内存大小,如果两个都指定,取不可移动内存数量较大的一个。如果都不指定,则不启动。
与其它内存域不同的是zone_movable不关联任何物理内存范围,该域的内存取自高端内存域或者普通内存域。
find_zone_movable_pfns_for_nodes用来计算每个node中zone_movable的内存数量,采用的内存区域通常是每个node的最高内存域,在函数find_usable_zone_for_movable中体现。
在对每个node分配zone_movable内存时,kernelcore会被平均分配到各个node:
kernelcore_node = required_kernelcore / usable_nodes;
在kernel alloc page时,如果gfp_flag同时指定了__gfp_highmem和__gfp_movable,则会从zone_movable内存域申请内存。
基于MAX78000FTHR的机器学习实时处理方案
直流电机的正反转控制电路图解
15W无线充电器真的能够提高Galaxy S9的充电速度吗?
北京电信在5G建设和创新中已取得了十分瞩目的成绩
燕麦水分测定仪原理和测试注意事项
你知道linux kernel内存碎片防治技术?
电力电缆YJV与KVV的定义以及二者之间的区别
关于过电压保护器的测试方法介绍
小米集团、格力电器近日先后公布了今年上半年业绩
微软Visual Studio 2022将在今年夏天发布
小寻T2儿童电话手表怎么样 值不值得买
dfrobotmicro:bit Go 基础套装介绍
锂离子电池概况及分类 锂电池电芯工艺流程
人工智能创新中心实验室正在开发专门针对医学界的技术
基于测试系统的FPGA测试方法研究与实现
水泥电阻在电源电路和分频器中的作用
马斯克:仍然可以实现 2020 年交付 50 万辆电动汽车的目标
树莓派火箭技术
可编程直流电源DP5000系列的特点
轮速传感器的分类以及工作原理解析