当前位置: 首页 > news >正文

中移(苏州)软件技术有限公司面试问题与解答(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

接前一篇文章&#xff1a;中移&#xff08;苏州&#xff09;软件技术有限公司面试问题与解答&#xff08;1&#xff09;—— 可信计算国密标准 本文参考以下文章&#xff1a; 启动期间的内存管理之初始化过程概述----Linux内存管理(九) Linux初始化 特此致谢&#xff01; 本…...

蓝桥杯、编程考级、NOC、全国青少年信息素养大赛—scratch列表考点

1、小小情报员&#xff08;202309scratch四级24题&#xff09; 1.准备工作 &#xff08;1&#xff09;选择背景 Colorful City&#xff1b; &#xff08;2&#xff09;保留角色小猫&#xff0c;选择角色Ballerina。 2.功能实现 &#xff08;1&#xff09;角色小猫初始位置…...

1.23 力扣图论

841. 钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n - 1 编号。最初&#xff0c;除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而&#xff0c;你不能在没有获得钥匙的时候进入锁住的房间。 当你进入一个房间&#xff0c;你可能会在里面找到一套不…...

Vue学习笔记9--vuex(专门在Vue中实现集中式状态(数据)管理的一个Vue插件)

一、vuex是什么&#xff1f; 概念&#xff1a;专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对vue应用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适用于…...

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)

服务&#xff08;Services&#xff09; 在Kong Gateway中&#xff0c;服务是代表外部上游&#xff08;upstream&#xff09;API或微服务的实体。例如&#xff0c;数据转换微服务、计费API等。 服务的主要属性是其URL。您可以使用一个字符串来指定URL&#xff0c;或者通过分别…...

IDEA更改页面不重启

IDEA更改页面不重启 idea若依 修改包名 idea 1、修改IDEA设置 File -> Settings -> Build Execution Deployment -> Build Project automatically 勾选2、勾选Running Ctrl Shift Alt / 然后选择 Registry&#xff0c;勾上 Compiler.autoMake.allow.when.app.runn…...

golang学习-channel管道

1、定义 管道是golang语言提供的goroutine间的通讯方式&#xff0c;channel可以让一个goroutine发送特定的值给另一个goroutine的通讯机制。 管道是引用类型。 golang语言中channel是一种特殊的类型。像一个队列一样&#xff0c;先进先出。 var 变量 chan 元素类型 var ch1 …...

oracle 12 查询数据库锁

在Oracle 12c中&#xff0c;查询数据库锁信息可以通过以下视图进行&#xff1a; v$locked_object&#xff1a;这个视图显示了当前被锁定的对象&#xff08;如表、行等&#xff09;的信息。 SELECT l.session_id sid, s.serial#, l.locked_mode,o.object_name,s.osuser,s.userna…...

【LeetCode-135】分发糖果(贪心)

LeetCode135.分发糖果 题目描述 老师想给孩子们分发糖果&#xff0c;有 N 个孩子站成了一条直线&#xff0c;老师会根据每个孩子的表现&#xff0c;预先给他们评分。 你需要按照以下要求&#xff0c;帮助老师给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。…...

5G_射频测试_发射机测量(四)

6.2 Base station output power 用于测量载波发射功率的大小&#xff0c;功率越大小区半径越大但是杂散也会越大 载波功率&#xff08;用频谱仪测&#xff09;天线口功率&#xff08;用功率计测&#xff09;载波功率是以RBW为单位的filter测量的积分功率不同带宽的多载波测试时…...

MySQL经典50题

目录 一、数据表介绍 二、练习题 1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数 2. 查询同时存在" 01 "课程和" 02 "课程的情况 3. 查询存在" 01 "课程但可能不存在" 02 "课程的情况…...

常用的Qt开源库分享

1. Qwt (https://qwt.sf.net): Qwt是一个基于Qt的数据可视化库&#xff0c;提供了绘制曲线、图表、仪表盘等功能。 2. QJson (https://qjson.sourceforge.net): QJson是一个用于JSON数据解析和生成的库&#xff0c;使Qt应用程序能够方便地处理JSON格式的数据。 3. QCustomP…...

Unity开发授权系统

Unity开发授权系统 引子 因为有些客户尾款到账不及时&#xff0c;因此研究了一套授权系统&#xff0c;当授权到期后&#xff0c;系统就提示软件授权已到期&#xff0c;不能继续使用云云&#xff0c;这样方便尾款的收回。 大体需求就是 时间相关性&#xff0c;可以自由设置授…...

一周时间,开发了一款封面图生成工具

介绍 这是一款封面图的制作工具&#xff0c;根据简单的配置即可生成一张好看的封面图&#xff0c;目前已有七款主题可以选择。做这个工具的初衷来自平时写文章&#xff0c;都为封面图发愁&#xff0c;去图片 网站上搜索很难找到满意的&#xff0c;而且当你要的图如果要搭配上文…...

【.NET Core】深入理解异步编程模型(APM)

【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09; 文章目录 【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09;一、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.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…...

在Python环境中运行R语言的配环境实用教程

前情提要 在做一些生物信息与医学统计的工作&#xff0c;本来偷懒希望只靠python完成的&#xff0c;结果还是需要用R语言&#xff0c;倒腾了一会儿&#xff0c;调成功了&#xff0c;就记录一下这个过程。 我的环境&#xff1a; win10, pycharm, R-4.3.2 首先&#xff0c;我们…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...