内存Linux 内核内存管理(1)

linux内存管理  时间:2021-01-15  阅读:()

Linux 内核内存管理(1)

Linux内核内存管理1

简介

内存管理是操作系统内核最复杂的部分之一(我认为它是最复杂的) 。在内核入口前最后的准备文中,我们刚好讲到了start_kernel函数调用之前内核发生的行为。 start_kernel函数在内核运行第一个init进程之前会初始化所有的内核(包括架构相关的特征)。你可能还记得在系统启动期间我们构造了early页表 identity页表和fixmap页表此时还没涉及复杂的内存管理。当start_kernel函数被调用时我们将过渡到更复杂的与内存管理有关的数据结构和技巧。为了能够很好的理解l inux内核的初始化过程我们需要清晰地了解这些技术。本章将综述l inux内核内存管理框架的各个不同部分和相应的API,首先介绍memblock。

Memblock

Memblock是在早期引导过程中管理内存的方法之一此时内核内存分配器还没运行。 Memblock以前被定义为Logical Memory Block(逻辑内存块),但根据Yinghai Lu的补丁,它被重命名为memblock。 x86_64架构的l inux内核就采用了这种方法。我们在内核入口前最后的准备文中已经提到了memblock。现在我们将进一步了解memblock是如何实现的。我们首先从数据结构着手来了解memblock。所有有关数据结构的定义都可以

在include/l inux/memblock.h头文件中找到。

第一个数据结构的名字如本节标题如下所示

该结构体包含五个域。如果bottom_up为true,则允许由下而上地分配内存

。 current_l imit指出了内存块的大小限制。接下来的三个域描述了内存块的类型 即预留型 内存型和物理内存型(如果宏

CONFIG_HAVE_MEMBLOCK_PHYS_MAP被定义了)。我们现在又接触到了一个数据结构memblock_type,它的定义如下

该结构体存储的是内存类型信息。它包含的域分别描述了当前内存块含有的内存区域数量所有内存区域的总共大小 已经分配的内存区域大小和一个指向memblock_region结构体的数组指针。memblock_region结构体描述了内存区域它的定义如下memblock_region结构体提供了内存区域的基地址和大小标志可以是

如果宏CONFIG_HAVE_MEMBLOCK_NODE_MAP被定义了memblock_region还提供一个整数域——numa节点选择器。

图示法可以用来展示以上结构体之间的关系

Memblock主要包含三个结构体 memblock,memblock_type和memblock_region。现在我们已了解了Memblock,接下来我们将看到Memblock的初始化过程。

Memblock初始化memblock的所有API描述在include/l inux/memblock.h头文件中所有这些API的实现在mm/memblock.c源文件中。在源文件的开头我们可以看到memblock结构体的初始化结构体memblock的初始化变量名和

结构体名相同——memblock。首先注

意__initdata_memblock宏它的定义如下

如果启用CONFIG_ARCH_DISCARD_MEMBLOCK宏配置选项memblock 代码会被放到. init代码段在内核启动完成后memblock代码会从. init代码段释放。

接下来的是memblock结构体中memblock_type memory,memblock_typereserved和memblock_type physmem的初始化。本文中我们只研

究memblock_type.regions的初始化过程。需要注意的是每一个memblock_type域都是通过memblock_region数组初始化的

每一个数组包含128个内存区域可以查看INIT_MEMBLOCK_REGIONS 的宏定义

需要注意的是所有的数组定义都带有__initdata_memblock宏该宏定义已

在memblock结构体初始化时提到过(如果忘了请回顾上文)memblock结构体中最后两个域 bottom_up内存分配模式被禁用当前Memblock的大小限制是

即0 x ffffffffffffff ff 。

一旦memblock结构体完成初始化我们接下来就研究MemblockAPI 。

MemblockAPI

我们已经完成了memblock结构体的初始化接下来我们将研究MemblockAPI和它的实现。在上文中我提到过所有关于memblock的实现

都在mm/memblock.c源文件中。要理

解memblock是如何工作和实现的我们首先看一下它的用法。在l inux内核中有几处用到了memblock例如arch/x86/kernel/e820.c中的函数memblock_x86_fi l l 。该函数遍历由e820提供的内存映射表并且通过memblock_add函数把内核预留的内存区域添加到memblock。既然我们首先遇到了memblock_add函数那就从它开始吧。memblock_add函数有两个参数物理基址和内存区域大小并且把该内存区域添加

到memblock。 memblock_add函数本身并没有什么它只是调用了

函数。我们传递的参数依次是 内存块类型(memory) 物理基址 内存区域大小最大节点数(0如果CONFIG_NODES_SHIFT没有在配置文件中设置不然就是CONFIG_NODES_SHIFT)和标志。memblock_add_range函数添加新的内存区域到内存块中。首先该函数检查给定的内存区域大小如果是0就返回。在这之后 memblock_add_range用给定

的memblock_type检查memblock结构体中是否存在内存区域。如果没有我们就用给定的值填充新的memory_region然后返回(我们已经在l inux内核内存管理框架的第一次接触一文中看到过实现)。如果memblock_type不为空我们就把新的内存区域添加到memblock_type类型的memblock中。

首先我们用如下代码获得内存区域的结束位置memblock_cap_size函数会设置size大小确保base+size不会溢出。该函数实现相当简单

memblock_cap_size返回size和ULLONG_MAX-base中的最小值。

在那之后我们得到了新的内存区域的结束地址 memblock_add_range 函数检查内存区域是否重叠并和已经添加到memblock中的内存区域合并。把新的内存区域插入到memblock中包含两步

把新的内存区域中非重叠的部分作为独立的区域加入到memblock合并所有相邻的内存区域接下来遍历所有已经存储的内存区域并检查有没有和新的内存区域重叠

如果新内存区域没有和已经存储在memblock的内存区域重叠把该新内存区域插入

到memblock中。这是第一次循环我们需要检查新内存区域是否可以放入内存块中并调用memblock_double_array:memblock_double_array函数加倍给定的内存区域大小然后把insert 设为true再转到repeat标签。第二次循环从repeat标签开始经过同样的循环然后

用memblock_insert_region函数把当前内存区域插入到内存块

由于我们在第一次循环中把insert设为true,现在memblock_insert_region函数将会被调用。 memblock_insert_region函数几乎和把新内存区域插入到空

的memblock_type代码块有同样的实现(见上文) 该函数获得最后一个内存区域

然后调用memmove函数移动该内存区域

紧接着填充新内存区域memblock_region的base域 size域等等 然

后增

大memblock_type的大小。最后memblock_add_range函数调

用memblock_merge_regions合并所有相邻且兼容的内存区域。

在第二种情况下新内存区域可能和已存储的内存区域重叠。例如在memblock中已经有了region

现在我们想把region2加到memblock中 region2含有以下基址和大小

本例中把新内存区域的基址设为重叠内存区域的结束地址

即base为0x1000。和第二次循环做法一样我们用以下代码把它添加到memblock本例中我们先插入overlappingportion(重叠部分)(只插入地址更高的部分 因为低地址部分已经在重叠内存区域) 然后插入剩余部分最后调

用memblock_merge_regions合并这些部分内存区域。memblock_merge_regions函数合并相邻且兼容的内存区域。该函数遍历所有memblock_type类型的内存区域每次取出两个邻近的内存区域——type->regions[i]和type->regions[i+1],然后检查它们是否有相同的标志属于相同的节点第一个内存区域的结束地址不等于第二个内存区域的基地址

如果这些条件一个都不满足更新第一个内存区域的大小

因为我们把第二个内存区域大小加到第一个内存区域大小所以我们要调用memmove函数把当前(this)内存区域后的每一个(靠每次循环)内存区域移动到其前一个内存区域

然后把memblock_type类型的内存区域数量减一

此后我们就会把两个内存区域合并为一个

以上就是memblock_add_range函数的全部工作原理。

还有memblock_reserve函数除了一处不同外其余均与memblock_add 函数一致

。 memblock_reserve函数把memblock_type.reserved类型的内存区域存到memblock中而不是memblck_type.memory。

Memblock不仅提供了添加memory和reserved类型的内存区域的API 还包括memblock_remove——从memblock中移除内存区域memblock_find_in_range——在给定的范围内找到未使用的内存memblock_free——释放memblcok中的内存区

域for_each_mem_range——反复迭代memblock

还有更多。 。 。

获取内存区域信息

Memblock也提供了API来获取memblock中已分配内存区域的信息分为两个部分 get_al located_memblock_memory_regions_info——获取内存区域信

息get_al located_memblock_reserved_regions_info——获取预留内存区域信息

这两个函数的实现很简单。

以get_al located_memblock_reserved_regions_info函数为例

该函数首先检查memblock是否包含预留内存区域。如果memblock 不包含则返回0否则

我们把预留内存区域的物理地址赋给addr然后返回已分配的数组经对齐过后的大小。对齐用的

是PAGE_ALIGN宏它依赖于页的大小

函数get_al located_memblock_memory_regions_info的实现和上面一样唯一不

同的是用到了memblock_type.memory而不是memblock_type.reserved。

Memblock调试

在memblock的实现中多次调用了memblock_dbg函数。如果在内核命令行传

入memblock=debug选项就会调用memblock_dbg函数。其实memblock_dbg仅仅是个宏

定义它的展开包含printk函数

例如 memblock_reserve函数调用了该宏

结果如下图

Memblock还支持debugfs。如果你的内核不是运行在X86架构上你可以访问

/sys/kernel/debug/memblock/memory/sys/kernel/debug/memblock/reserved /sys/kernel/debug/memblock/physmem来获得memblock内容的转储。

总结

关于l inux内核内存管理第一部分到此结束。如果有任何疑问或建议在twitter0xAX上联

系我或给我发邮件或提交一个issue。

超链接e820numadebugfsl inux 内核内存管理框架的第一次接触

妮妮云(43元/月 ) 香港 8核8G 43元/月 美国 8核8G

妮妮云的来历妮妮云是 789 陈总 张总 三方共同投资建立的网站 本着“良心 便宜 稳定”的初衷 为小白用户避免被坑妮妮云的市场定位妮妮云主要代理市场稳定速度的云服务器产品,避免新手购买云服务器的时候众多商家不知道如何选择,妮妮云就帮你选择好了产品,无需承担购买风险,不用担心出现被跑路 被诈骗的情况。妮妮云的售后保证妮妮云退款 通过于合作商的友好协商,云服务器提供2天内全额退款,超过2天不退款 物...

SugarHosts糖果主机圣诞节促销 美国/香港虚拟主机低至6折

SugarHosts 糖果主机商我们算是比较熟悉的,早年学会建站的时候开始就用的糖果虚拟主机,目前他们家还算是为数不多提供虚拟主机的商家,有提供香港、美国、德国等虚拟主机机房。香港机房CN2速度比较快,美国机房有提供优化线路和普通线路适合外贸业务。德国欧洲机房适合欧洲业务的虚拟主机。糖果主机商一般是不会发布黑五活动的,他们在圣圣诞节促销活动是有的,我们看到糖果主机商发布的圣诞节促销虚拟主机低至6折...

TMTHosting:夏季优惠,美国西雅图VPS月付7折,年付65折,美国服务器95折AS4837线路

tmthosting怎么样?tmthosting家本站也分享过多次,之前也是不温不火的商家,加上商家的价格略贵,之到斯巴达商家出现,这个商家才被中国用户熟知,原因就是斯巴达家的机器是三网回程AS4837线路,而且也没有多余的加价,斯巴达家断货后,有朋友发现TMTHosting竟然也在同一机房,所以大家就都入手了TMTHosting家的机器。目前,TMTHosting商家放出了夏季优惠,针对VPS推...

linux内存管理为你推荐
美国主机租用在哪里可以租用美国服务器?国外主机空间可以购买国外主机(空间一样吗?)来做私服吗?台湾vps哪个地区的VPS从大陆访问快呢。深圳网站空间深圳宝安网站设计,深圳网站空间,哪里做的最好???万网虚拟主机万网虚拟主机可以做几个网站上海虚拟主机谁能告诉我杭州哪个公司的虚拟主机最好,机房最好是上海或浙江的.郑州虚拟主机什么是双线虚拟主机?长沙虚拟主机长沙IDC,求长沙本地虚拟主机,大伙推荐推荐长沙虚拟主机长沙哪里虚拟主机和主机托管比较关好!备案域名网站备案分为哪几种?域名备案跟网站备案有什么不同?
视频空间租用 域名备案信息查询 美国主机网 搜狗抢票助手 php免费空间 河南服务器 空间论坛 宁波服务器 怎样建立邮箱 可外链网盘 新睿云 512mb 免费asp空间 美国盐湖城 七牛云存储 云销售系统 免费主页空间 阿里云邮箱怎么注册 脚本大全 第八届中美互联网论坛 更多