读书笔记|Linux内核设计与实现

这本书是学习linux内核原理的必读推荐书目之一!它对linux内核的设计原理进行了详细的说明,并介绍了具体的实现部分,结合源码可以很好地理解linux内核。

在简单翻阅了一遍之后,我带着以下几个疑问,整理了相关知识点:

1、内核是什么时候加载运行的?

2、应用程序、内核和硬件之间的关系?

3、进程管理、内存管理和进程地址空间?

其实书上的知识还是那些,可能在不同的阶段去理解,原来没什么感觉,现在看来,一切都变得那么清晰起来。所以说,对操作系统的理解和学习是打通任督二脉的事情,也更好的理解了我们所做的事情到底处于什么样的层次,性能调优也有了从源头开始的思路!

内核是什么时候加载运行的?bootloader将压缩的内核复制到内存空间;内核自解压;然后运行内核,流程如下:1、入口在arch/arm/kernel/head-armv.S

2、查找处理器类型

__lookup_processor_type

__lookup_architecture_type

3、初始化页表:__create_page_tables

4、初始化C代码空间

5、跳转到C代码中,start_kernel

start_kernel在init/main.c中,完成内核的启动过程;

start_kernel()–>rest_init()–>kernel_init()–>do_basic_setup()–>do_initcalls()

另外,BIOS->GRUB->INIT程序的启动过程可以参考:https://www.php.cn/link/6868e581382cc1c0d24e352a4e262ac0

应用程序、内核和硬件之间的关系?读书笔记|Linux内核设计与实现应用程序使用库提供的open,read,write函数打开我们的设备文件。库根据open,read,write函数传入的参数执行”swi”指令,这条指令引发CPU异常,进入内核。内核的异常处理函数根据这些参数找到对应的驱动程序,返回一个文件句柄给库,进而返回给应用程序。应用程序得到句柄后,使用库提供的write,ioctl函数发出控制命令。库根据write,ioctl函数传入的参数执行swi指令,引起CPU异常,进入内核。内核的异常处理函数根据这些参数调用驱动程序的相关函数。根据《Linux内核设计与实现》说明,CPU在某个任何特定的时间点上的活动必然概括为下列三种之一:

运行于用户空间,执行用户进程;运行于内核空间,处于进程上下文,代表某个特定的进程执行;运行于内核空间,处于中断上下文,与内核进程无关处理某个特定的终端;驱动程序与应用程序的区别

1、应用程序以main开始,驱动程序没有main,它以一个模块初始化函数作为入口。

2、应用程序从头到尾执行一个任务,驱动程序完成初始化之后不再运行,等待系统调用。

3、应用程序可以使用GLIBC等标准C函数库,驱动程序不能使用标准C库。

Linux设备驱动作为一个Linux内核模块存在,模块都有两个接口函数,模块初始化函数和模块退出函数。

上面提到的驱动程序的注册。一般是由模块初始化函数来实现的。模块退出函数则用于取消内核注册,释放资源。 可见只有运行了驱动的这个模块初始化函数之后,驱动程序才能够被注册,内核才能找到设备驱动。 那么什么时候模块初始化函数才获得运行呢?动态加载时,即运行insmod时。静态加载时模块编译进内核系统初始化时会自动调用这个模块初始化函数。

用户态与内核态

系统运行时一般情况下,分为用户态和内核态,这两种运行态下的数据互不可见。驱动程序是内核的一部分,工作在内核态,应用程序工作在用户态。这样就存在数据空间访问的问题:无法通过指针直接将二者的数据地址进行传递。问题的解决办法是:系统提供一系列函数帮助完成数据空间转换:例如,get_user、put_user、copy_from_user、copy_to_user等函数。

Linux操作系统为什么分为用户态和内核态,简单以一句话来说是为了安全, 在CPU的所有指令中,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。

系统调用:与内核通信的关键,系统调用包括系统调用号,系统调用的实现,系统调用上下文等;

读书笔记|Linux内核设计与实现图来源:https://www.php.cn/link/13d763a5838ca85acd2d4ff824ab03ea

进程管理描述进程的数据结构,进程的创建,fork、clone等方法创建进程,进程的关系,进程结束;进程调度;进程树;

进程就是运行的程序;进程除了可执行的代码段,还包括打开的文件,挂起的信号,内核内部数据,处理器状态,内存地址空间及一个或多个执行线程、全局变量的数据段等等;线程是在进程中活动的对象,线程是内核调度的对象;

进程的创建、运行、和销毁通常使用到的几个方法:fork()、clone()、exec()、exit();

Linux的进程创建时使用到写时拷贝的技术(copy-on-write)来实现。写时拷贝是一种推迟甚至免除拷贝数据的技术,内核此时并不复制整个进程地址空间,而是让父进程和子进程以只读方式共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。

内存管理内存管理简单理解是操作系统为了让多个应用程序安全、便捷地使用内存单元,实现的一种内存虚拟化技术!解决的是:

1、多进程使用同一个内存硬件资源;

2、内存数据隔离;

3、内存数据安全;

4、内存使用监控;

通过MMU的访存

MMU会先查找TLB中的虚拟地址表

如果TLB中没有虚拟地址的入口,硬件从主存储器中的转换表中获取转换与访问权限。

ARM的MMU页表格式

MMU支持基于节或者页的存储器访问。

节:1MB的存储器块

大页:64KB的存储器块

小页:4KB的存储器块

微页:1KB的存储器块

页表的级别

存在主存储器内的转换页表有两个级别:

第一级表:存储节转换表与指向第二级表的指针

第二级表:

(1)存储大页和小页的转换表。

(2)存储微页的转换表。

MMU/Cache line

CPU L1/L2高速缓存

页高速缓存:Linux内核实现的磁盘缓存,主要用来减少对磁盘的I/O操作。具体来讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问。

进程地址空间进程地址空间由进程可寻址的虚拟内存组成;每个应用程序可见的地址空间是相同的,如下图:

读书笔记|Linux内核设计与实现理解了这张图,可能就真正理解了用户态和内核态是怎么回事了!

一个进程的地址空间和另一个进程的地址空间即使有相同的内存地址,实际上也彼此互不相干。

内存区域可以包括各种内存对象:

1、可执行文件代码的内存映射,成为代码段(text section);

2、可执行文件中的已初始化全局变量的内存映射,称为数据段(data section);

3、包含未初始化全局变量、也就是bss段的零页的内存映射;

4、用于进程用户控件栈的零页的内存映射;

每一个诸如C库或者动态链接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间;

5、任何内存映射文件;

6、任何共享内存段;

7、任何匿名的内存映射,如malloc分配的内存;

以上就是读书笔记|Linux内核设计与实现的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/72396.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
仅此一家!今年只有华为Mate 80系列搭载可变光圈
上一篇 2025年11月13日 16:08:09
谷歌浏览器提示“喔唷,崩溃啦”怎么分析原因_Chrome页面崩溃问题原因分析与解决
下一篇 2025年11月13日 16:11:12

相关推荐

  • composer require-dev和require有什么不同_Composer Require与Require-Dev区别解析

    require用于声明项目运行必需的依赖,如框架、数据库组件和第三方SDK,这些包会随项目部署到生产环境;2. require-dev用于声明仅在开发和测试阶段需要的工具,如PHPUnit、PHPStan、Faker等,不会默认部署到生产环境;3. 安装时composer install根据环境决定…

    2026年5月10日
    1000
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • 如何让动态追加元素的类事件生效?

    如何在追加元素后使其绑定类事件生效 在页面中引入三方 JavaScript 类并通过添加相应 class 来调用事件方法是一种常见的做法。然而,如果通过 JavaScript 追加标签元素,即使添加了对应的 class,事件也可能无法生效。 为了解决这个问题,可以尝试以下步骤: 检查追加的标签是否为…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • 理解编程指令:当结果正确,但实现方式不符要求时

    本文探讨了在编程实践中,即使程序输出了正确的结果,但若其实现方式未能严格遵循既定指令,仍可能被视为“不正确”的问题。我们将通过具体示例,对比直接求和与累加求和两种实现策略,强调理解和遵守编程规范的重要性,以确保代码的健壮性、可维护性及符合项目要求。 在软件开发过程中,我们经常会遇到这样的情况:编写的…

    2026年5月10日
    000
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • php常量怎么用_PHP常量(define/const)定义与使用方法

    PHP中可通过define函数和const关键字定义常量,用于存储不可变值。define适用于全局作用域,支持动态名称和条件定义,如define(‘SITE_NAME’, ‘MyWebsite’);const在编译时生效,语法简洁但限制多,只能在类或全…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000
  • Python命令怎样使用profile分析脚本性能 Python命令性能分析的基础教程

    使用Python的cProfile模块分析脚本性能最直接的方式是通过命令行执行python -m cProfile your_script.py,它会输出每个函数的调用次数、总耗时、累积耗时等关键指标,帮助定位性能瓶颈;为进一步分析,可将结果保存为文件python -m cProfile -o ou…

    2026年5月10日
    000
  • 使用 WebCodecs VideoDecoder 实现精确逐帧回退

    本文档旨在解决在使用 WebCodecs VideoDecoder 进行视频解码时,实现精确逐帧回退的问题。通过比较帧的时间戳与目标帧的时间戳,可以避免渲染中间帧,从而提高用户体验。本文将提供详细的解决方案和示例代码,帮助开发者实现精确的视频帧控制。 在使用 WebCodecs VideoDecod…

    2026年5月10日
    000
  • 如何插入查询结果数据_SQL插入Select查询结果方法

    如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法

    使用INSERT INTO…SELECT语句可高效插入数据,通过NOT EXISTS、LEFT JOIN、MERGE语句或唯一约束避免重复;表结构不一致时可通过别名、类型转换、默认值或计算字段处理;结合存储过程可提升可维护性,支持参数化与动态SQL。 将查询结果数据插入到另一个表中,可以…

    2026年5月10日 用户投稿
    000
  • Discord.py 交互按钮超时与持久化解决方案

    本教程旨在解决Discord.py中交互按钮在一段时间后出现“This Interaction Failed”错误的问题。我们将深入探讨视图(View)的超时机制,并提供通过正确设置timeout参数以及利用bot.add_view()方法实现按钮持久化的具体方案,确保您的机器人交互功能稳定可靠,即…

    2026年5月10日
    000
  • Debian Copilot的社区活跃度如何

    debian copilot是codeberg社区维护的ai助手,旨在为debian用户提供服务。尽管搜索结果中没有直接提供关于debian copilot社区支持活跃度的具体数据,但我们可以通过debian社区的整体活跃度和特点来推断其活跃性。 Debian社区的一般情况: Debian拥有详尽的…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信