中移(苏州)软件技术有限公司面试问题与解答(2)—— Linux内核内存初始化的完整流程1
接前一篇文章:中移(苏州)软件技术有限公司面试问题与解答(1)—— 可信计算国密标准
本文参考以下文章:
启动期间的内存管理之初始化过程概述----Linux内存管理(九)
Linux初始化
特此致谢!
本文对于中移(苏州)软件技术有限公司面试问题中的“(8)Linux内核内存初始化的完整流程。”进行解答与解析。
实际上早有此心,把Linux内核尤其是进程管理、内存管理和文件系统的代码都筛一遍。但是一直由于种种原因没有花大力气真正干。正好借着这个机会,开始做这个事情。先从面试中问到的内存管理开始。
1. Linux系统启动过程中的内存初始化概述
在Linux系统初始化过程中,必须建立内存管理的数据结构以及很多事务。因为Linux内核在内存管理完全初始化之前就需要使用内存。在系统启动期间,使用了额外的简化的内存管理模块。随后在初始化完成后,将旧的模块丢弃掉。
可以把Linux内核的内存管理分三个阶段:
| 阶段 | 起点 | 终点 | 过程描述 |
|---|---|---|---|
| 第一阶段 | 系统启动 | bootmem或者memblock初始化完成前 | 此阶段只能使用memblock_reserve函数分配内存,早期内核中使用init_bootmem_done=1标识此阶段结束 |
| 第二阶段 | bootmem或者memblock初始化完成 | buddy初始化完成前 | 引导内存分配器bootmem或者memblock接受内存的管理工作,早期内核中使用mem_init_done=1标记此阶段的结束 |
| 第三阶段 | buddy初始化完成 | 系统停止运行 | 可以用cache和buddy分配内存 |
2. start_kernel函数中的内存管理相关内容
首先我们来看看start_kernel()是如何初始化系统的。start_kerne函数在init/main.c中,代码如下(笔者使用的内核源码版本为6.7,在这个时间点上是比较新的版本):
asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{char *command_line;char *after_dashes;set_task_stack_end_magic(&init_task);smp_setup_processor_id();debug_objects_early_init();init_vmlinux_build_id();cgroup_init_early();local_irq_disable();early_boot_irqs_disabled = true;/** Interrupts are still disabled. Do necessary setups, then* enable them.*/boot_cpu_init();page_address_init();pr_notice("%s", linux_banner);early_security_init();setup_arch(&command_line);setup_boot_config();setup_command_line(command_line);setup_nr_cpu_ids();setup_per_cpu_areas();smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */boot_cpu_hotplug_init();pr_notice("Kernel command line: %s\n", saved_command_line);/* parameters may set static keys */jump_label_init();parse_early_param();after_dashes = parse_args("Booting kernel",static_command_line, __start___param,__stop___param - __start___param,-1, -1, NULL, &unknown_bootoption);print_unknown_bootoptions();if (!IS_ERR_OR_NULL(after_dashes))parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,NULL, set_init_arg);if (extra_init_args)parse_args("Setting extra init args", extra_init_args,NULL, 0, -1, -1, NULL, set_init_arg);/* Architectural and non-timekeeping rng init, before allocator init */random_init_early(command_line);/** These use large bootmem allocations and must precede* initalization of page allocator*/setup_log_buf(0);vfs_caches_init_early();sort_main_extable();trap_init();mm_core_init();poking_init();ftrace_init();/* trace_printk can be enabled here */early_trace_init();/** Set up the scheduler prior starting any interrupts (such as the* timer interrupt). Full topology setup happens at smp_init()* time - but meanwhile we still have a functioning scheduler.*/sched_init();if (WARN(!irqs_disabled(),"Interrupts were enabled *very* early, fixing it\n"))local_irq_disable();radix_tree_init();maple_tree_init();/** Set up housekeeping before setting up workqueues to allow the unbound* workqueue to take non-housekeeping into account.*/housekeeping_init();/** Allow workqueue creation and work item queueing/cancelling* early. Work item execution depends on kthreads and starts after* workqueue_init().*/workqueue_init_early();rcu_init();/* Trace events are available after this */trace_init();if (initcall_debug)initcall_debug_enable();context_tracking_init();/* init some links before init_ISA_irqs() */early_irq_init();init_IRQ();tick_init();rcu_init_nohz();init_timers();srcu_init();hrtimers_init();softirq_init();timekeeping_init();time_init();/* This must be after timekeeping is initialized */random_init();/* These make use of the fully initialized rng */kfence_init();boot_init_stack_canary();perf_event_init();profile_init();call_function_init();WARN(!irqs_disabled(), "Interrupts were enabled early\n");early_boot_irqs_disabled = false;local_irq_enable();kmem_cache_init_late();/** HACK ALERT! This is early. We're enabling the console before* we've done PCI setups etc, and console_init() must be aware of* this. But we do want output early, in case something goes wrong.*/console_init();if (panic_later)panic("Too many boot %s vars at `%s'", panic_later,panic_param);lockdep_init();/** Need to run this when irqs are enabled, because it wants* to self-test [hard/soft]-irqs on/off lock inversion bugs* too:*/locking_selftest();#ifdef CONFIG_BLK_DEV_INITRDif (initrd_start && !initrd_below_start_ok &&page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",page_to_pfn(virt_to_page((void *)initrd_start)),min_low_pfn);initrd_start = 0;}
#endifsetup_per_cpu_pageset();numa_policy_init();acpi_early_init();if (late_time_init)late_time_init();sched_clock_init();calibrate_delay();arch_cpu_finalize_init();pid_idr_init();anon_vma_init();
#ifdef CONFIG_X86if (efi_enabled(EFI_RUNTIME_SERVICES))efi_enter_virtual_mode();
#endifthread_stack_cache_init();cred_init();fork_init();proc_caches_init();uts_ns_init();key_init();security_init();dbg_late_init();net_ns_init();vfs_caches_init();pagecache_init();signals_init();seq_file_init();proc_root_init();nsfs_init();cpuset_init();cgroup_init();taskstats_init_early();delayacct_init();acpi_subsystem_init();arch_post_acpi_subsys_init();kcsan_init();/* Do the rest non-__init'ed, we're now alive */arch_call_rest_init();/** Avoid stack canaries in callers of boot_init_stack_canary for gcc-10* and older.*/
#if !__has_attribute(__no_stack_protector__)prevent_tail_call_optimization();
#endif
}
可以看到,start_kernel函数代码很长,有200行。在此只截取出其中与内存管理初始化相关的部分,如下所示:
asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{……setup_arch(&command_line);……setup_per_cpu_areas();……mm_core_init();……kmem_cache_init_late();……setup_per_cpu_pageset();numa_policy_init();……anon_vma_init();……pagecache_init();……/* Do the rest non-__init'ed, we're now alive */arch_call_rest_init();
}
| 函数 | 功能 | 备注 |
|---|---|---|
| page_address_init | 初始化内核用于查找物理页面地址的数据结构 | |
| setup_arch | 是一个特定于体系结构的设置函数,其中的一项任务是负责初始化自举分配器 | |
| setup_per_cpu_areas | 给每个CPU分配内存,并拷贝.data.percpu段的数据 | |
| build_all_zonelists | 建立并初始化结点和内存域的数据结构 | 已移至mm_core_init函数中 |
| mm_core_init | 建立了内核的内存分配器。其中通过mem_init函数停用bootmem分配器并迁移到实际的内存管理器(比如伙伴系统), 然后调用kmem_cache_init函数初始化内核内部用于小块内存区的分配器 | |
| kmem_cache_init_late | 在kmem_cache_init函数之后,完善分配器的缓存机制,当前3个可用的内核内存分配器slab、slob、slub都会定义此函数 | |
| kmemleak_init | 提供了一种可选的内核泄漏检测,其方法类似于跟踪内存收集器。当独立的对象没有被释放时,其报告记录在/sys/kernel/debug/kmemleak中,kmemcheck()能够帮助定位大多数内存错误的上下文 | 已移至mm_core_init函数中 |
| setup_per_cpu_pageset | 初始化CPU高速缓存行,为pagesets的第一个数组元素分配内存,换句话说,其实就是第一个系统处理器分配 | |
| numa_policy_init | 初始化NUMA策略 | |
| anon_vma_init | 匿名虚拟内存域初始化,创建anon_vma的slab缓存 | |
| pagecache_init | 页高速缓存的初始化 | |
| arch_call_rest_init | 用于在系统引导时调用平台特定的初始化函数 |
3. 内存初始化过程概述
在操作系统初始化的初期,操作系统只是获取到了内存的基本信息,内存管理的数据结构都没有建立。而这些数据结构创建的过程本身就是一个内存分配的过程。那么问题就来了:内存管理数据结构需要分配到相应的内存,才能完成做后续工作;但是它所做的工作本身就是为了内存能够分配。此时还没有一个内存管理器去负责分配和回收内存,而又不可能将所有的内存信息都静态地创建并初始化,那么怎么分配内存管理器所需要的内存呢?这就是一个典型的“鸡生蛋、蛋生鸡”的问题。不过甭管是先有鸡还是先有蛋,总归要先有二者之一,才能有后续的循环。
类比于鸡和蛋问题,我们先要实现一个满足要求的但是可能效率不高的笨家伙(内存管理器),用它来负责系统初始化初期的内存管理,最重要地,用它来初始化我们内存的数据结构,直到我们真正的内存管理器被初始化完成并能投入使用。之后就可以将旧的内存管理器丢掉。
因此在系统启动过程期间,内核使用了一个额外的简化形式的内存管理模块早期的引导内存分配器(boot memory allocator–bootmem分配器)或者memblock,用于在启动阶段早期分配内存。而在系统初始化完成后,该分配器被内核抛弃,然后初始化了一套新的更加完善的内存分配器。
系统启动
| ---- 第一阶段
bootmem或者memblock初始化完成
| ---- 第二阶段
伙伴系统以及slab cache初始化完成
| ---- 第三阶段
系统终止运行
从下一回开始对start_kernel()中的内存管理相关函数进行详细解析。
相关文章:
中移(苏州)软件技术有限公司面试问题与解答(2)—— Linux内核内存初始化的完整流程1
接前一篇文章:中移(苏州)软件技术有限公司面试问题与解答(1)—— 可信计算国密标准 本文参考以下文章: 启动期间的内存管理之初始化过程概述----Linux内存管理(九) Linux初始化 特此致谢! 本…...
蓝桥杯、编程考级、NOC、全国青少年信息素养大赛—scratch列表考点
1、小小情报员(202309scratch四级24题) 1.准备工作 (1)选择背景 Colorful City; (2)保留角色小猫,选择角色Ballerina。 2.功能实现 (1)角色小猫初始位置…...
1.23 力扣图论
841. 钥匙和房间 有 n 个房间,房间按从 0 到 n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。 当你进入一个房间,你可能会在里面找到一套不…...
Vue学习笔记9--vuex(专门在Vue中实现集中式状态(数据)管理的一个Vue插件)
一、vuex是什么? 概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于…...
Operation
contents 服务器一、相关概念1.1 云服务器与实例1.2 关于域名解析延时与80端口1.3 关于备案1.4 关于SSL证书1.5 关于SSL证书的签发1.6 关于SSL证书的部署1.7 关于LNMP和LAMP1.8 关于bt面板 二、单服务器单一级域名多网站2.1 创建多个二级域名2.2 解析二级域名绑定到服务器上2.3…...
Kong关键概念 - 服务(Services)
服务(Services) 在Kong Gateway中,服务是代表外部上游(upstream)API或微服务的实体。例如,数据转换微服务、计费API等。 服务的主要属性是其URL。您可以使用一个字符串来指定URL,或者通过分别…...
IDEA更改页面不重启
IDEA更改页面不重启 idea若依 修改包名 idea 1、修改IDEA设置 File -> Settings -> Build Execution Deployment -> Build Project automatically 勾选2、勾选Running Ctrl Shift Alt / 然后选择 Registry,勾上 Compiler.autoMake.allow.when.app.runn…...
golang学习-channel管道
1、定义 管道是golang语言提供的goroutine间的通讯方式,channel可以让一个goroutine发送特定的值给另一个goroutine的通讯机制。 管道是引用类型。 golang语言中channel是一种特殊的类型。像一个队列一样,先进先出。 var 变量 chan 元素类型 var ch1 …...
oracle 12 查询数据库锁
在Oracle 12c中,查询数据库锁信息可以通过以下视图进行: v$locked_object:这个视图显示了当前被锁定的对象(如表、行等)的信息。 SELECT l.session_id sid, s.serial#, l.locked_mode,o.object_name,s.osuser,s.userna…...
【LeetCode-135】分发糖果(贪心)
LeetCode135.分发糖果 题目描述 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。 你需要按照以下要求,帮助老师给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果。…...
5G_射频测试_发射机测量(四)
6.2 Base station output power 用于测量载波发射功率的大小,功率越大小区半径越大但是杂散也会越大 载波功率(用频谱仪测)天线口功率(用功率计测)载波功率是以RBW为单位的filter测量的积分功率不同带宽的多载波测试时…...
MySQL经典50题
目录 一、数据表介绍 二、练习题 1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数 2. 查询同时存在" 01 "课程和" 02 "课程的情况 3. 查询存在" 01 "课程但可能不存在" 02 "课程的情况…...
常用的Qt开源库分享
1. Qwt (https://qwt.sf.net): Qwt是一个基于Qt的数据可视化库,提供了绘制曲线、图表、仪表盘等功能。 2. QJson (https://qjson.sourceforge.net): QJson是一个用于JSON数据解析和生成的库,使Qt应用程序能够方便地处理JSON格式的数据。 3. QCustomP…...
Unity开发授权系统
Unity开发授权系统 引子 因为有些客户尾款到账不及时,因此研究了一套授权系统,当授权到期后,系统就提示软件授权已到期,不能继续使用云云,这样方便尾款的收回。 大体需求就是 时间相关性,可以自由设置授…...
一周时间,开发了一款封面图生成工具
介绍 这是一款封面图的制作工具,根据简单的配置即可生成一张好看的封面图,目前已有七款主题可以选择。做这个工具的初衷来自平时写文章,都为封面图发愁,去图片 网站上搜索很难找到满意的,而且当你要的图如果要搭配上文…...
【.NET Core】深入理解异步编程模型(APM)
【.NET Core】深入理解异步编程模型(APM) 文章目录 【.NET Core】深入理解异步编程模型(APM)一、APM概述二、IAsyncResult接口2.1 BeginInvoke2.2 EndInvoke2.3 IAsyncResult属性2.4 IAsyncResult异步演示 三、通过结束异步操作来…...
pyqtgraph绘图类
pyqtgraph绘图类 pyqtgraph绘图有四种方法: 方法描述pyqtgraph.plot()创建一个新的QWindow用来绘制数据PlotWidget.plot()在已存在的QWidget上绘制数据PlotItem.plot()在已存在的QWidget上绘制数据GraphicsLayout.addPlot()在网格布局中添加一个绘图 上面四个方法都接收同样…...
C#6-10新增的内容
目录 异常筛选器 属性语法 表达式主体定义 Null 条件运算符 ?. 和 ?[] 使用 $ 的字符串内插 nameof 表达式 元组类型 模糊匹配 本地函数 Expression-bodied 成员 Reference 变量 ?、??和??= .. 模式匹配功能(C# 9) Record init c#8.NET Framework 4.8…...
【立创EDA-PCB设计基础】3.网络表概念解读+板框绘制
前言:本文对网络表概念解读板框绘制(确定PCB板子轮廓) 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2,将设计的原理图转为了PCB,在PCB界面下出现了所有的封装,以及所有的飞线属性&…...
在Python环境中运行R语言的配环境实用教程
前情提要 在做一些生物信息与医学统计的工作,本来偷懒希望只靠python完成的,结果还是需要用R语言,倒腾了一会儿,调成功了,就记录一下这个过程。 我的环境: win10, pycharm, R-4.3.2 首先,我们…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...
基于django+vue的健身房管理系统-vue
开发语言:Python框架:djangoPython版本:python3.8数据库:mysql 5.7数据库工具:Navicat12开发软件:PyCharm 系统展示 会员信息管理 员工信息管理 会员卡类型管理 健身项目管理 会员卡管理 摘要 健身房管理…...
