谈谈如何学习Linux内核

简介: 谈谈如何学习Linux内核

一、确立高度,明确目标

高度决定视角,视角决定行动

      在学习内核过程中最容易犯的错误,也是非常难掌握的其实是你站在一个什么样的高度上去学习。站在什么样的高度去学习也与自身的能力相关,所以这个问题其实更多是在新开始学习的学习者感到非常痛苦的一件事。一方面又希望自己能学懂,但是又不知道如何开始入手。

我列举几个常见的例子:

(1) 一开始就看源码,最开始我也做过这种事,内核有什么都不知道,结果就想着啃0.11的内核,结果很显然,2天立马放弃,完全看不懂。

(2) 翻开书从第一页开始往下啃,如果这本书比较薄还好,如果比较厚,比如《深入Linux内核架构》,那看2天也得放弃。

(3) 不喜欢看目录,不喜欢快速浏览,就想着一个一个字眼的往下抠。如果本身有一定基础,看的时候还不会觉得腻,但是很快就发现,看了半天,什么都没有记住。

    还有很多类似的问题,这些都是我们平时学习的时候特别容易出现的一些误区。这些其实都是没有正确审视自己的能力,胡乱挑选高度导致。

高度是什么?

       高度越高,也就是越偏向于理解各种抽象概念,倾向于构建对整体结构的一个认知,忽略一些不必要细节,不关心技术实现手段。高度越低,也就是越偏向于对使用技术的选择,倾向于代码实现的各个细节,但是前提一般会在某个抽象的概念领域内进行各种细节性的讨论。

       我们的大脑更倾向于理解抽象的内容,但是在行动时,我们却更倾向于去把握细节性的内容。结果导致的内容就是,我们总是希望通过学习细节来构造对抽象概念的理解,最后被细节性内容中各种噪声干扰思绪,产生一种“这东西好难”的错觉。在理解了这点,那高度对我们的行为有和指导意义也就呼之欲出了?
       以读书为例。站的越高,意味着自己看的内容越粗糙,也就是看书的时候不会去逐字逐句的看,而是一个章节一个章节的看,极端的情况就是只看目录,在这个过程中主要集中精力构建整体结构,对核心的概念进行抽象。这时候学的内容都相对表面,但是好处就是对以后的学习有很强的指导意义,缺点很明显,会让人底气不足,而且在达到一定程度后,很容易到达瓶颈,发觉怎么看都看不懂了。站的越低,意味着自己看的内容很细致,看书的时候就是一个个字眼的扣,极端情况就是开始阅读源码,去看开源社区的各种问题。但是就像诗句说的,站的越低,也就常有一种“不识庐山真面目,只缘身在此山中”的感觉。这种情况下特别容易被各种细节干扰,例如为什么要有这些参数,为什么这里需要判断这个条件等等这些细枝末节的问题。

如何运用高度

       以前对一篇博文印象很深刻,作者理解的学习曲线划分成了两个比较大的过程,上升的过程就是一个不断学习积累的过程,而平缓没有增长的过程则是对之前积累到饱和的知识进行消化的过程。我将这个学习过程进行进一步的划分,我觉得在学习积累的前半部分应该以偏向学习抽象概念为主,而后半部分应该偏向学习实现细节。

640.jpg

 

      所以个人的心得是从高到低的学习,在一个新的学习阶段,应该先多花点时间学习一些概念化的内容,这时候切忌去看具体的实现,而是多考虑如何在大脑中构建各种抽象模型

     对整体的架构有所概念了,然后开始学习一些细节性的内容,比如开始看些源码,抠写书上的字眼,读读一些具体的博客什么的。

二、学习小Tips

1.如何看书

       不要从第一页开始翻 ,不要一页一页的翻

  • 花些时间看看前言,在很多书的前言部分,作者会告诉你,整本书的结构应该是什么样,应该要以什么样的顺序去阅读,在阅读的时候应该站在什么样的角度去阅读,这是作者的建议,有什么比作者的建议更值得我们听取呢!?
  • 不要寄托希望于一次看懂一本书,越是好的书越是要反复的看,但是很多人对这个反复理解有问题,认为反复的看就是一页页翻,重复看几遍。其实不是这样,每次反复应该让自己换一个高度,第一次翻的时候可以站在很高的高度,看一本书甚至只需要1天的时间,重复几次后,站的高度应该越低,很可能看一个章节需要1天时间,甚至有时候看一页就需要1天的时间。
  • 一本书的目录就像你在沙漠中的指南针,不要忽略目录的作用。每次翻开书,在决定自己看什么之前,花点时间浏览下目录,让自己回忆(了解)要看的章节的架构,带着这个结构去学习事半功倍。
  • 带着问题去看书,这点很难,因为提什么样的问题和你选择的高度密切相关,站的高度越高,那就越不要给自己提一些细节性的问题,反之则反之。

2.如何看代码

       如果开始看代码,一定要记住,自己已经站在一个非常底层的高度度了,能够有能力阅读代码,就意味着你必须对整体的结构有比较清晰的认识,如果你都不知道这个结构,那看代码为时太早。

       无论是什么样的代码,其实思路都很类似,即使Linux内核是用C这种面过程的语言编写,但是这么多年发展下来,Linux内核已经带有了大量面对对象编程的特点。

        在看代码的时候也是有两种不同的高度可以选择,我先解释其中最细致的一种:

(1)如何阅读函数

         一个函数写下来经常上百行,但是你需要一行一行的看么?肯定不能,那清晰认识一个函数的结构就很重要。

         一个函数就是为了解决一个问题,函数名基本都能说明其功能,函数参数是输入,返回值就是输出,函数体就是整体的执行逻辑。在函数体内部,也基本都是类似的逻辑,先是对各种输入参数进行检查,然后书写功能逻辑,然后构造输出的结果。所以一个函数写下来总是这样的一种结构。

输出结果 函数名(输入)
{
if (输入的参数有问题)
{
 异常处理,跳出
}
       准备参数

功能逻辑


构造输出结果


返回输出结果
}


      一个函数其实就是一个方法,阅读的难度比书写的难度要低,书写代码需要考虑的问题非常多,但是在阅读代码的时候问题就简单很多,很多书写代码过程中需要考虑的问题在阅读代码的过程中就不需要考虑 。

  • 函数名:在书写代码过程中需要考虑一个函数的函数名需要能够精确表达出这个函数所具备的功能,所以经常存在各种名目规范。而阅读代码过程则可以通过阅读函数名大致了解这个函数的功能。
  • 注释:在编写代码的时候,都会建议添加对应的函数注释,解释函数体的功能和一些注意事项;在阅读过程中可以选择性的阅读这些注释(注意:是选择性阅读,千万不要每个注释都读)
  • 输入参数:在书写代码的时候,这部分的内容也是很头疼的内容,不仅需要确定需要哪些输入,还需要输入的形式,而且还需要精确定义每个输入参数的语义;但是在阅读代码的过程中,这部分内容基本可以忽略,我们很少会关系所看到的函数需要哪些参数输入。
  • 输出结果:在书写代码的时候,这部分也是很头疼的一件事,因为精确定义输出结果也是非常困难和麻烦的一件事;在阅读代码过程中,也需要注意输出结果,不然一个函数执行了老半天,结果连输出结果是什么都没概念,也太失败了点。
  • 参数检测:在编写代码过着中非常烦的一件事,每个人都希望调用函数的人会传入正确的参数,但是根本做不到,结果每次都要花费一定精力对输入参数的边界、非空等进行检查;在阅读代码过程中,根本不需要阅读这部分的代码,恰恰这部分内容在每个函数体中占据了相当一部分的位置;
  • 参数准备:编写代码的过程中,因为函数体内部的逻辑需要进行很多准备,所以常常需要有一个参数准备的过程;而阅读代码的过程基本可以忽略这部分的逻辑,或者快速浏览这部分逻辑,这里恰恰是很多新手花费大量精力纠缠的内容,其实没必要在这里纠结,跳过就好。
  • 功能逻辑:这部分是函数体中最为精华的部分,而且代码编写起来也是相当的麻烦,被各种逻辑弄的死去火来,最后还需要重构等等手段;在阅读代码过程中,这部分其实很难把握,因为功能逻辑可能被封装在另外一个函数内部,这时候大家会习惯性的继续深入看,结果弄的自己更加混乱,又比如有的时候几个功能逻辑点组成了一套逻辑,但是大家却将这部分逻辑割裂来看,结果总感觉读的很别扭。这部分内容需要一些经验,但是有一个指导,就是在看这部分代码的时候要注意自己所站的高度,选择采用何种策略。
  • 构造输出结果:函数体内部还会花费大量的代码进行对最后返回结果的构造工作,就像搭积木一样;不过在阅读代码的时候,我们并不需要花费太多精力在这些逻辑上,多注意注意一些返回结果的语义。

     阅读代码还有很多技巧,例如如何在带有goto语句的代码中快速理解逻辑,如何界定那些注释是可以忽略的,如何将一些代码逻辑看成一块整体内容,何时应该跳到更深的一层函数阅读等等。这些都需要平时的经验积累。

(2)如何在大量的代码中游刃有余

      看代码有一个粒度问题,我们不能一行一行的看,也不能一个一个函数的看,我之前提到了,Linux内核有大量面向对象编程的影子,所以在看大量代码的时候,必须学会面向对象编程的思维模式。这样对自己在大量代码阅读中提供大量参考意见。

      或许有人会告诉你,面向对象编程就是弄明白什么是对象、如何写一个class就可以了。确实,学习面向对象编程,弄明白对象是基础,不过我觉得可以再拔高一点,理解一些更抽象的概念,在这些抽象概念的指导下去学习,可以有更多的指导意义。

  • 层:层并不是面向对象编程特有,但是理解层是很重要的,我们遇到的典型的层就是网络协议栈,为什么我们网络协议会有那么多层,就因为需要处理的事情太多,我们不得不将内容一块块的分割,分割的时候,发现用层进行组织,可以让结构更加清晰,所以你以后会发现,大量的系统都会带有层的味道。linux内核中带有大量的层设计,如网络协议栈有层,内存管理与寻址有层,文件I/O也有层。
  • 领域模型:领域模型就是一个系统中最为核心的几个抽象实体,一个系统,基本就是围绕着领域模型展开,在学习内核不同的子系统的时候,一定要花大量的精力在领域模型上,切记!!!在Linux内核上也有大量的领域模型,例如在虚拟文件系统部分存在4大抽象inode,dentry,file等。在进程调度系统的最核心抽象是task_struct。在进程地址空间则有mm_struct,address_space等这些核心的领域模型。我感觉可以花费80%的时间在理解这些领域模型上。
  • 领域驱动类:领域模型内部其实是大量的属性组成,但是如果只有属性,没有一个执行的方法,那这个领域模型也不能发挥作用,面向对象编程的做法就是将这些方法编程领域驱动类,说的直白一些就是接口。在Linux中就是那些函数指针和对应的回调函数。平时看代码,大家会花费大量的时间去看各个回调函数,这个其实是吃力不讨好的办法,与其花大量的心思去看各个回调函数的实现,不如多思考下,为什么会有这些操作方法,它们是如何抽象出来的。


如果能够理解上述的这几个抽象,那在大量代码中如何游刃有余就相对容易了,有一个简单的套路:
(1) 在较高的角度,弄明白一个系统为了解决什么问题,应该有哪些抽象

(2) 在对整体结构有所了解以后,花心思看看这些抽象对应的领域模型,因为一般情况领域模型很庞大,所以看的时候也需要有步骤的进行拆解学习。

(3) 在对领域模型有所了解后,开始看领域驱动类,想明白为什么会有这些操作。

(4) 在上述准备好后,就可以花费一些时间去看各个函数的具体实现,并且在看的过程中多思考领域模型为什么这么设计。


相关文章
|
5天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
26 6
|
10天前
|
存储 安全 Linux
|
4天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
19 9
|
2天前
|
缓存 负载均衡 Linux
深入理解Linux内核调度器
本文探讨了Linux操作系统核心组件之一——内核调度器的工作原理和设计哲学。不同于常规的技术文章,本摘要旨在提供一种全新的视角来审视Linux内核的调度机制,通过分析其对系统性能的影响以及在多核处理器环境下的表现,揭示调度器如何平衡公平性和效率。文章进一步讨论了完全公平调度器(CFS)的设计细节,包括它如何处理不同优先级的任务、如何进行负载均衡以及它是如何适应现代多核架构的挑战。此外,本文还简要概述了Linux调度器的未来发展方向,包括对实时任务支持的改进和对异构计算环境的适应性。
18 6
|
3天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
18 5
|
1天前
|
算法 Linux 调度
深入理解Linux内核调度器:从基础到优化####
本文旨在通过剖析Linux操作系统的心脏——内核调度器,为读者揭开其高效管理CPU资源的神秘面纱。不同于传统的摘要概述,本文将直接以一段精简代码片段作为引子,展示一个简化版的任务调度逻辑,随后逐步深入,详细探讨Linux内核调度器的工作原理、关键数据结构、调度算法演变以及性能调优策略,旨在为开发者与系统管理员提供一份实用的技术指南。 ####
14 4
|
4天前
|
算法 Unix Linux
深入理解Linux内核调度器:原理与优化
本文探讨了Linux操作系统的心脏——内核调度器(Scheduler)的工作原理,以及如何通过参数调整和代码优化来提高系统性能。不同于常规摘要仅概述内容,本摘要旨在激发读者对Linux内核调度机制深层次运作的兴趣,并简要介绍文章将覆盖的关键话题,如调度算法、实时性增强及节能策略等。
|
5天前
|
存储 监控 安全
Linux内核调优的艺术:从基础到高级###
本文深入探讨了Linux操作系统的心脏——内核的调优方法。文章首先概述了Linux内核的基本结构与工作原理,随后详细阐述了内核调优的重要性及基本原则。通过具体的参数调整示例(如sysctl、/proc/sys目录中的设置),文章展示了如何根据实际应用场景优化系统性能,包括提升CPU利用率、内存管理效率以及I/O性能等关键方面。最后,介绍了一些高级工具和技术,如perf、eBPF和SystemTap,用于更深层次的性能分析和问题定位。本文旨在为系统管理员和高级用户提供实用的内核调优策略,以最大化Linux系统的效率和稳定性。 ###
|
4天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
6天前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
22 6