1、32位的计算机对应的地址总线只有32根,所以计算机一次最多寻址范围2^32,即4GB。理论上也可以进行高32位、低32位共64位的寻址,但考虑到逻辑上设计复杂,和效率较低等因素,该分段方法不被采用。
2、L1、L2缓存每个CPU核心都单独有,L3缓存是多个CPU核心共有
3、CPU 并不会直接和每一种存储器设备直接打交道,而是每一种存储器设备只和它相邻一层的存储器设备打交道。
4、多核处理器中,只有数据先从内存中读取到高速缓存中才能修改。为了(1)保存数据一致性,其他核才知道指向相同的变量被修改,才能更新状态。(2)提高访问的性能,若后面用到这个变量,每次访问数据都要从内存中读取。
5、Cache Line(缓存行):是Cache高速缓存从内存中读取数据的基本单位。通常是一组连续的缓存行的形式,大小为64字节。
6、在Linux内核中,进程和线程都是用task_struct结构体表示的,线程的task_struct中部分资源是共享的进程中已创建的资源,例如内存地址空间、代码段、文件描述符等。Linux中的线程又被称为轻量级进程(线程的task_struct比进程的task_struct承载资源较少)。
7、Linux 内核里的调度器,调度的对象就是 task_struct,也称为任务。
8、Linux中任务优先级数值越小,级别越高:
实时任务:对响应时间要求高,优先级在0~99范围内。
普通任务:响应时间没有很高要求,优先级在100~139内。
9、nice值映射到100~139,是给普通任务用的,用以调节普通任务优先级。
10、Linux中每个任务都有自己的任务调度策略,任务调度策略是针对每个任务,而不是整个系统。(改变任务调度策略,可能会影响任务优先级)
11、
SCHED_OTHER(默认的时间片轮转调度策略)
SCHED_FIFO(先进先出调度策略)
SCHED_RR(轮转调度策略)
12、调度类:为保证高优先级任务尽早执行,分为以下几种调度类:
Deadline和Realtime这两个调度类,都是应用于实时任务的
而Fair调度类是应用于普通任务,都是由CFS调度器管理的
13、多核CPU:具有并行处理能力,也就是可以同时执行多个线程或任务,每个核心可以独立的执行指令,多个任务同一时间同时进行。
单核CPU:多任务时,具有并发处理能力。每个任务执行一小段时间,就切换到另一个任务,宏观看,一段时间内执行了多个任务。
13、ELF是可执行文件链接格式,它是 Linux 操作系统中可执行文件的存储格式。
执行ELF文件(可执行文件)的时候,会通过「装载器」把ELF文件装载到内存里,CPU 读取内存中的指令和数据,程序就被执行起来了。、
14、宏内核:系统内核的所有模块,如进程调度、内存管理、文件系统、设备驱动等,都运行在内核态。
微内核(华为鸿蒙):只保留了最基本的能力,如进程调度、虚拟机内存、终断等。其他一些放到了用户空间,如驱动程序、文件系统等。
区别:微内核功能少,可移植性高,但相比宏内核,由于驱动程序不在内核中,而驱动程序会频繁调用底层能力,驱动和硬件设备就需要频繁切换到内核态,会带来性能损耗。
原因在于:驱动程序需要执行特级指令时(如访问硬件寄存器、I/O操作等)时,需要切换为内核态。执行完特权操作后,又需要切换回用户态,继续执行其他非特权操作。
混合内核:内核中有一个微内核,其他模块在此基础上搭建,实现时和宏内核类似,大部分服务都在内核中,就像是宏内核的方式包裹着一个微内核。
内存管理
1、(1)操作系统使得多个程序可以同时运行(同时有多个进程),每个进程都有自己的虚拟空间映射到物理空间中。
(2)虚拟地址空间内部又分为内核空间和用户空间两部分。
(3)虽然每个进程都各自有独立的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存。这样,进程切换到内核态后,就可以很方便地访问内核空间内存。
2、通过malloc()函数申请内存时,实际上申请的是虚拟内存,并不会分配物理内存。只有当应用程序读写了该块虚拟内存,CPU会去访问这个虚拟内存,发现未映射到物理内存上,CPU就会产生缺页中断,进程从用户态切换到内核态,将缺页中断交给内核的Page Fault Handle(缺页中断函数)处理。
3、缺页中断处理函数会看是否有空闲的物理内存:
(1)如果有,就直接分配物理内存,并建立虚拟内存与物理内存之间的映射关系。
(2)如果没有空闲的物理内存,那么内核就会开始进行回收内存 (opens new window)的工作,如果回收内存工作结束后,空闲的物理内存仍然无法满足此次物理内存的申请,那么内核就会触发 OOM (Out of Memory)机制(最后的大招)。
4、swap机制:内存存在压力时,开始触发内存回收行为,将不常访问的内存写入磁盘,然后释放这些内存,当需要访问时,再从磁盘读出。相当于将一块磁盘空间当作内存来用。
5、swap触发情况:(1)内存不足:直接内存回收(同步)(2)内存限制,kSwapd,空闲内存低于一定水平时触发(异步)
6、子进程共享了父进程的虚拟内存空间,就会变为线程,是否共享地址空间几乎是进程和线程之间的本质区别。但Linux内核并不区别对待它们,线程对其来说就是一个共享特定资源的线程而已。
7、CPU只会访问虚拟内存地址。
8、并发和并行:
9、所谓操作系统的任务调度,实际上的调度对象是线程,而进程只是给线程提供了虚拟内存、全局变量等资源。
10、线程和进程:(1) 当进程只有一个线程时,可以认为进程就等于线程(主线程)。(2)当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时是不需要修改的;
11、线程上下文切换要看是不是同一个进程的,同一个进程切换的数据少很多。
12、线程通信方式:同个进程下的线程之间都是共享进程的资源,只要是共享变量(多个线程可以同时访问和修改的变量)都可以做到线程间通信。
线程间关注的不是通信方式,而是多线程竞争共享资源的问题,信号量同样可在线程间实现同步与互斥。
13、线程是调度的基本单位,进程则是资源分配的基本单位。
14:零拷贝:全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。没有在内存层面去拷贝数据。
15、Page Cache(磁盘高速缓存):是操作系统中用于存储磁盘数据的一种缓存机制,用于加速磁盘 I/O 操作。当程序需要读取磁盘上的数据时,操作系统会将数据读取到内存中的一个页面(Page)中,并在需要时将其写回磁盘。由操作系统管理。
Cache Line(缓存行):是计算机体系结构中用于存储 CPU 缓存中数据的最小单位。由 CPU 控制。
16、4GB 物理内存的机器上,申请 8G 内存时,32位操作系统(理论上)最多申请3G(用户空间)虚拟内存,而64位可以使用128T大小的虚拟内存,因为如果不读写虚拟内存,操作系统就不会分配物理内存,所以申请8G内存没问题。
17、匿名页是像进程的堆、栈等没有实际载体(物理内存中)的数据,可能会被再次访问,不能直接释放,用一个保存匿名页的磁盘载体,即swap分区保存。
18、LRU算法,将最不常用的内存空间换出到磁盘中(链表尾部通常为最不常访问的)
19、预读失效:提前加载进来的页,没有被访问。
避免预读失效:实现了两个链表:活跃链表(active_list)和非活跃LRU链表(inactive_list)。预读页就加入inactive_list链表。
20、缓存污染:批量读取数据时,很多数据就读取了一次,而之前活跃在LRU链表中的热点数据就会被淘汰,当这些热点数据再次被访问时,由于缓存未命中,会产生大量的磁盘I/O,导致系统性能下降。
避免缓存污染:Linux中只有再内存也被访问第二次时,才将页从inactive list升到active list里。
21、用户态和内核态间的隔离关系
(1)对用户态操作硬件的限制:通过CPU指令集权限,硬件限制。用户态权限为ring3权限最低,只能使用常规cpu指令集,不能操作硬件资源。内核态权限为ring0,具有对所有硬件的操作权限。
(2)用户态不能访问内核态空间:用户态只能操作0-3G范围内的低位虚拟空间地址。内核态则0-4G的虚拟空间地址都可以操作,尤其3-4G只能由内核态操作,并且该部分指向的物理内存是所有进程共享的。
(3)对用户态空间的限制方式:(1)页表中的权限位(2)cpu指令集权限
用户空间若想访问内核中资源,需要通过系统调用下跳到内核态来实现。
(4)用户态与内核态的切换:
- 保护用户态线程(上下文、寄存器、用户栈等)
- 复制用户态参数,用户栈切到内核栈,进入内核态
- 额外检查(因为内核代码对用户不信任)
- 执行内核态代码
- 复制内核态代码执行结果,回到用户态
- 恢复用户态现场(上下文、寄存器、用户栈等)
可参考:「操作系统」什么是用户态和内核态?为什么要区分-CSDN博客
进程管理
1、process control block PCB(进程控制块)中包含的信息:(1)进程标识符、用户标识符(2)进程当前状态如new,ready等、进程优先级(3)打开的文件列表和使用的I/O设备信息。(4)CPU中寄存器的值,进程切换时,状态信息保存在相应的PCB中。
2、PCB通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。如就绪队列、阻塞队列。
3、进程是由内核管理和调度的,所以进程的切换只能发生在内核态。
进程上下文切换:不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。
通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行。
4、线程是调度的基本单位,进程是资源拥有的基本单位.
5、线程上下文切换:
当两个线程不是属于同一个进程,则切换的过程就跟进程上下文切换一样;
当两个线程是属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据;
6、线程控制块(Thread Control Block, TCB)
操作系统不参与用户线程的调度,如果一个线程发起了系统调用而阻塞,那进程所包含的用户线程都不能执行了。
内核线程是由操作系统管理的,线程对应的 TCB 自然是放在操作系统里的,这样线程的创建、终止和管理都是由操作系统负责。
7、从就绪态 -> 运行态:当进程被创建时,会进入到就绪队列,操作系统会从就绪队列选择一个进程运行;
从运行态 -> 阻塞态:当进程发生 I/O 事件而阻塞时,操作系统必须选择另外一个进程运行;
从运行态 -> 结束态:当进程退出结束后,操作系统得从就绪队列选择另外一个进程运行;
8、调度算法:先来先服务、最短作业优先、高响应比优先、时间片轮转、最高优先级、多级反馈队列调度算法
9、信号量会导致睡眠。睡眠后会有一个睡眠等待队列,存放等待信号量的线程或进程。
文件系统:
1、Linux 最经典的一句话是:「一切皆文件」,不仅普通的文件和目录,就连块设备、管道、socket 等,也都是统一交给文件系统管理的。
2、Linux 文件系统会为每个文件分配两个数据结构:索引节点(index node)和目录项(directory entry),它们主要用来记录文件的元信息和目录层次结构。
(1)索引节点,也就是 inode,用来记录文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点存储在硬盘中,同样占用磁盘空间。
(2)目录项,也就是 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存。
索引节点唯一标识一个文件,而目录项记录着文件的名字,所以目录项和索引节点的关系是多对一,也就是,一个文件可以有多个别名。(硬链接的实现)
(3)目录也是文件,也是用索引节点唯一标识,和普通文件不同的是,普通文件在磁盘里面保存的是文件数据,而目录文件在磁盘里面保存子目录或文件
在磁盘中的存储情况:
超级块,用来存储文件系统的详细信息,比如块个数、块大小、空闲块等等。
索引节点区,用来存储索引节点;
数据块区,用来存储文件或目录数据;
3、文件系统,根据存储位置的不同,把文件系统分为三类:
磁盘的文件系统,直接把数据存储在磁盘中,比如 Ext 2/3/4、XFS 等都是这类文件系统。
内存的文件系统,这类文件系统的数据不是存储在硬盘的,而是占用内存空间,我们经常用到的 /proc 和 /sys 文件系统都属于这一类,读写这类文件,实际上是读写内核中相关的数据。
网络的文件系统,用来访问其他计算机主机数据的文件系统,比如 NFS、SMB 等等。
4、打开文件表:我们打开了一个文件后,操作系统会跟踪进程打开的所有文件。操作系统为每个进程维护一个打开文件表,文件表里的每一项代表「文件描述符」
打开文件的状态和信息:
文件指针、文件打开计数器、文件磁盘位置、访问权限
5、文件存储方式:连续空间存放、非连续空间存放(链表和索引)
6、目录的存储:和普通文件不同的是,普通文件的块里面保存的是文件数据,而目录文件的块里面保存的是目录里面一项一项的文件信息。(如文件名、文件 inode、文件类型等)
7、有时候我们希望给某个文件取个别名,那么在 Linux 中可以通过硬链接(Hard Link) 和软链接(Symbolic Link) 的方式来实现。
8、硬链接是多个目录项中的「索引节点」指向一个文件,也就是指向同一个 inode。不可用于跨文件系统的。
软链接相当于重新创建一个文件,这个文件有独立的 inode,但是这个文件的内容是另外一个文件的路径,所以访问软链接的时候,实际上相当于访问到了另外一个文件。
9、文件I/O分为:(1)缓冲与非缓冲 I/O(2)直接与非直接 I/O(3)阻塞与非阻塞 I/O VS 同步与异步 I/O
10、非阻塞 I/O,非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好.
11、为了解决这种傻乎乎轮询方式,于是 I/O 多路复用技术就出来了,如 select、poll,它是通过 I/O 事件分发,当内核数据准备好时,再以事件通知应用程序进行操作。
整个流程要比阻塞 IO 要复杂,似乎也更浪费性能。但 I/O 多路复用接口最大的优势在于,用户可以在一个线程内同时处理多个 socket 的 IO 请求
12、实际上,无论是阻塞 I/O、非阻塞 I/O,还是基于非阻塞 I/O 的多路复用都是同步调用。因为它们在 read 调用时,内核将数据从内核空间拷贝到应用程序空间,过程都是需要等待的。
13、而真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。
当我们发起 aio_read 之后,就立即返回,内核自动将数据从内核空间拷贝到应用程序空间,这个拷贝过程同样是异步的,内核自动完成的。应用程序并不需要主动发起拷贝动作。
14、I/O 是分为两个过程:(1)数据准备的过程(2)数据从内核空间拷贝到用户进程缓冲区的过程
15、阻塞 I/O 会阻塞在「过程 1 」和「过程 2」,而非阻塞 I/O 和基于非阻塞 I/O 的多路复用只会阻塞在「过程 2」,所以这三个都可以认为是同步 I/O。
16、异步 I/O 则不同,「过程 1 」和「过程 2 」都不会阻塞。
17、软链接,又称符号链接即将一个路径名链接到一个文件。软链接文件内存储的是源文件的路径。可以在不同目录下创建,源文件位置变动或删除时,会失效。ln -s file link
硬链接,是对原文件起了一个别名,源文件删除后不影响硬链接(inode还在),源文件其实也是个硬链接,每少一个硬链接,链接数减1。ln file link