操作系统的秘密


前言

操作系统,位于底层硬件和用户之间,是两者沟通的桥梁。用户态受程序员控制,内核态受操作系统控制。


一、GNU

1.1 什么是GNU?

GNU是一个自由软件构成的操作系统,与Unix兼容,该系统通常与Linux内核一起使用。
GNU计划开发了很多系统部件,GCC (GNU编译器套装)就是其中之一。

1.2 GCC

案例:

gcc demo.c -o demo.exe

该命令可以将我们编写的程序编译成一个二进制可执行文件
在 Linux 下,可执行文件格式为 ELF ,在 Windows 下是 EXE。

二、内核

2.1 内核的职责

进程的形式来分配CPU时间,以虚拟内存的形式来分配物理内存,以文件的形式来管理IO设备。

2.2 封装层

抽象来说,是APP(函数)与内核之间的封装层。
通过系统调用(system call),我们可以像使用普通函数那样向操作系统请求服务,当然,直接使用系统调用是非常繁琐的,因此通常会在这之上提供一层封装。
在这里插入图片描述
操作系统需要提供两种接口:

  • 给用户提供操作接口。
  • 给程序员提供编程接口。

2.2.1 内核提供了什么?

处理TCP/IP协议栈数据,从网卡上收发数据,网络编程,文件IO,创建进程,创建线程等等。

2.2.2 Windows内核与Linux内核

Windows内核是Windows NT内核,给程序员提供编程接口的是Windows API。
Linux只是一个开源的内核,如果一定要找一个类似Windows API的东西话那就是libc,也就是C标准库,这里同样包括了对系统调用的封装以及一些库函数,但libc不包含创建带有图形界面应用程序的功能。

2.3 标准库

2.3.1 什么是标准库?

本质上,一门语言就是一堆规则(rules),就像if之后必须是一个括号(),这个括号中必须是一个bool表达式,等等。
C/C++对外发布的标准中包含两部分内容:

  1. C/C++支持哪些特性;
  2. C/C++API,程序员可以在他们的C/C++程序中直接调用这些API。

这些API就被称为标准库(Standard Library),malloc也是标准库的一部分。

  • Linux中以.so结尾的文件被称为动态链接库,被实现好打包到了动态链接库中了。

编译器gcc在编译程序是默认情况下就自动链接了标准库,Linux下标准库的实现被称为GNU C Library,也被称为glibc。
Windows中C/C++标准库被称为了Universal C Runtime Library(Universal CRT,简称UCRT),即UCRTBASE.DLL。

2.4 预编译器(preprocessor)

2.4.1什么是预编译器?

编译器在将代码翻译成机器指令前,预编译器找到源文件中#include指定的文件,然后copy这些文件的内容并粘贴到#include这一行所在的位置。

2.4.2 头文件stdio.h

  • 头文件是不会被编译的
  • 如果一个头文件放到了<>中,那么预编译器会在系统头文件所在的路径下开始找,在Linux下这个路径是/usr/include

2.5 链接器

典型的链接器,把由编译器或汇编器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体,该实体能够被操作系统直接执行。
采用链接器的原因是,修补代码比重新编译和汇编要快得多。

三.编译器是怎么执行函数的?

编译器是一个将高级语言翻译为低级语言的程序。
步骤如下:

  • 经过词法分析,编译器得到token,如T_While while,T_LeftParen (,“T_While”,“T_LeftParen”就是token

  • 编译器在扫描出各个token后根据规则将其用树的形式表示出来,这颗树就被称为语法树
    在这里插入图片描述

  • 语法树是不是合理的:语义分析

  • 根据语法树生成中间代码:代码生成

  • 中间代码优化
    在这里插入图片描述

  • 代码生成
    在这里插入图片描述
    函数运行起来后占用的内存,栈(栈区)这种结构就可以用来保存函数调用信息。

四.I/O密集型

4.1 I/O(input/output)是什么?

I/O可以理解为内存与外部数据之间的数据copy。

4.2 I/O的底层逻辑

4.2.1 什么是时间片?

分时操作系统分配给每个正在运行的进程微观上的一段CPU时间。

4.2.2 阻塞式I/O(blocking I/O)

操作系统通过CPU,执行A进程中读取文件的代码read(buff),外设I/O操作过慢并产生了阻(block),操作系统保存暂停的A进程进入阻塞队列,磁盘driver(驱动)copy数据到进程的buff中(进程暂停并不妨碍数据copy),操作系统从就绪队列中找出B进程,将cpu的PC寄存器指向B进程暂停时执行的机器指令位置,运行B进程,磁盘中断后系统将A队列从阻塞队列放到就绪队列,时间片后执行buff已满的进程A。
buff指cpu的缓冲器,cpu,内存,外设的信息传送中转站。

五.I/O多路复用

I/O多路复用的目标,是实现一个线程可以监视多个文件句柄。

5.1.什么是文件描述符(文件句柄)?

文件是N byte(8个bit)的序列,使用文件需要文件描述符(file descriptors,一个数字,Windows中是文件句柄 file handles)。

5.2 什么是“事件驱动”?

在持续事务管理过程中,进行决策的一种策略,即跟随当前时间点上出现的事件,调动可用资源,执行相关任务,使不断出现的问题得以解决,防止事务堆积

5.3 I/O多路复用的过程

我们拿到一堆fd,用函数告诉内核监视fd,可以进行I/O读写的时候进行返回。

5.4 I/O多路复用三剑客

本质上,select、poll、epoll都是阻塞式I/O,也就是我们常说的同步I/O。

  • select : fd不能超过1024个,需要拷贝到内核(操作系统的核心)中,函数返回后需要遍历找出;
  • poll : fd超过1024个,其他同select;
  • epoll : epoll_ctl只操作有变化的fd,和内核的共享内存保存可读可写的fd,代替进程找到要处理的fd。

六.三种不同的内存

现代计算机系统CPU和内存之间其实是有一个cache的层级结构。
在这里插入图片描述

  • SRAM:通电则数据恒常,主板或者CPU上的高速缓存(主要用于Level2 Cache)
  • DRAM:数据需要周期性更新
  • ROM:只读内存,单独的内部存储器,在主板bios芯片中,不会因为断电而消失

比如Redis的数据就存在内存,且使用epoll,不在网络I/O上浪费过多的时间。实现对多个FD读写的监控,提高性能。

6.1 程序局部性原理

  • CPU执行指令符合28定律,大部分时间都在执行那一少部分指令。
  • 少部分在程序执行过程经常用到内存空间,集中到SRAM。
  • CPU访问内存首先查找Cache,容量不大,但是很小的cache也能有很高的命中率。

6.2 不一致问题

6.2.1 什么是MESI协议?

多核CPU的cache内存一致性协议。
解释:当每个CPU从cache中读取数据时,保证所有cache和内存中数据的一致性。

6.2.2 存在不一致的情况

  1. 情况一
    cache中的值更新了,但内存中的值还是旧的,可以用同步缓存更新(write-through)解决,更新cache时也更新内存。
  2. 情况二
    CPU写cache时,cache中没有相应的内存数据,需要从内存加载到cache,更新cache,再更新内存(效率低)。
  • 用异步更新缓存解决
    当CPU写内存时,直接更新cache,当包含该数据的cache块被剔除时再更新到内存中。

七.指令集(ISA)

CPU是整个计算机系统的核心,CPU指令集ISA更是核心中的核心,其包括“加法”,“从内存把数据搬运到寄存器”,“跳转”,“比较大小”…等指令。

7.1 什么是“微代码”(Microcode)?

简单指令,可组成复杂指令。微代码是CPU以及机器指令的中间层,机器指令相对于微代码来说是“更高级的语言”,机器指令(需编译器)对程序员来说可见,但微代码对程序员来说不可见,程序员无法直接使用微代码来控制CPU。

7.2 精简指令集(RISC)

不需要微代码这层中间抽象,CPU内部的操作细节暴露给编译器,编译器可以对其进行控制。

7.2.1 RISC体系结构的基本思想

RISC通过减少指令种类、规范指令格式和简化寻址方式等方法,方便处理器内部的并行处理,提高超大规模集成电路(VLSI)器件的使用效率,从而大幅度地提高处理器的性能。

7.2.2 精简指令如何操作CPU读写内存?(案例)

在精简指令集下,有专用的 load 和 store 两条机器指令来负责内存的读写,其它指令只能操作CPU内部的寄存器。
Load指令会将数据从内存搬到寄存器;PROD指令会计算两个寄存器中数字的乘积;Store指令把寄存器中的数据写回内存,因此如果一个程序员想完成上述任务就需要写这些汇编指令:

LOAD RA, A
LOAD RB, B
PROD RA, RB
STORE A, R

他们尝试让每条指令执行的时间都差不多一样,尽可能让流水线更高效地处理机器指令。

7.3 复杂指令集(CISC)

7.3.1 产生原因:

最初的程序都是面向CPU直接用汇编来写程序,没有面向对象和设计模式,这个时期的程序员写代码只需要看看ISA就可以。

7.3.2 功能

强化指令功能(微指令),减少程序的指令条数,让程序员或者编译器使用最少的代码就能完成任务,因为这会节省程序本身占用的内存空间,但这加重了CPU 硬件本身的复杂度,需要的晶体管数量也更多。

  • 当今普遍存在于桌面PC以及服务器端的x86架构(非X64)就是基于复杂指令集CISC。

八.虚拟内存

操作系统对每个进程都维护一个假象,即,每个进程独占系统内存资源;让程序员可以认为在写程序时有一大块连续的内存可以使用,也就是虚拟内存(假的地址空间)。
现代CPU内部有一个叫做MMU的模块将假的地址A转换为真的地址B:
在这里插入图片描述
有了虚拟内存,内存其实也是一层cache,是磁盘的cache,也就是说查内存也有可能不会命中,因为内存中的数据可能被虚拟内存系统放到磁盘中了,如果内存也不能命中,就要查磁盘了。

九.mmap

9.1 什么是mmap?

将一个文件或对象映射进内存
磁盘上保存的文件在程序员眼里也是存放一段连续的空间中,我们可以直接把这段空间映射到进程的内存中。
我们必须先把磁盘中的文件读取到内存中,然后在内存中再按照字节粒度来操作文件内容。

例:

假设文件长度是100字节,我们把该文件映射到了进程的内存中,地址是从600 ~ 800,那么当你直接读写600 ~ 800这段内存时,实际上就是在直接操作磁盘文件,用户程序依然可以直接修改这块内存,此后操作系统会在背后将修改内容写回磁盘。
在这里插入图片描述
mmap一方面在于为了创建并维持地址空间文件的映射关系,内核中需要有特定的数据结构来实现这一映射,这当然是有性能开销的,除此之外另一点就是缺页问题,page fault。

9.2 什么是缺页(page fault)?

用mmap将文件映射到进程地址空间后,当我们引用的一段其对应的文件内容,还没有真正加载到内存后,就会产生中断,这个中断就是缺页。
操作系统检测到这一信号后把相应的文件内容加载到内存。

  • 当物理内存的空闲空间所剩无几时,虚拟内存会把你进程地址空间中不常用的部分扔出去。

9.3 动态链接库

mmap把该库直接映射到各个进程的地址空间中,尽管每个进程都认为自己地址空间中加载了该库,但实际上该库在内存中只有一份。
在这里插入图片描述
mmap仅仅将文件内容映射到了进程地址空间中,并没有真正的拷贝到进程地址空间,这节省了一次从内核态到用户态的数据拷贝。
除了mmap之外,还有其它办法也可以实现零拷贝。

十.零拷贝

计算机处理的任务大体可以分为两类:CPU密集型与IO密集型。
高效IO的秘诀,就是尽量少让CPU参与进来。

  1. Sendfile:首先DMA机制会把数据从磁盘拷贝到内核buf中,接下来把数据从内核buf拷贝到相应的socket buf中,最后利用DMA机制将数据从socket buf拷贝到网卡中。
  2. DMA Gather Copy:无需再将内核文件buf中的数据拷贝到socket buf,而是网卡利用DMA Gather Copy机制将消息头以及需要传输的数据等直接组装在一起发送出去。
    在这里插入图片描述
  3. Pipe(Linux中用于进程间通信的管道)
    既然用户态无需对该数据有任何操作,那么为什么不让数据传输直接在内核态中进行呢?
    以网络服务器为例,DMA把数据从磁盘拷贝到文件buf,然后将数据写入管道,当在再次调用splice后将数据从管道读入socket buf中,然后通过DMA发送出去,值得注意的是向管道写数据以及从管道读数据并没有真正的拷贝数据,而仅仅传递的是该数据相关的必要信息。
    在这里插入图片描述
    总结:老老实实用read/write,相比这些所谓的技巧,内存拷贝没有那么糟糕。

十一.空闲任务进程

为了让调度器永远能从队列中找到一个可供运行的进程,内核设计者创建了一个叫做空闲任务的进程,这个进程就是Windows 下的“系统空闲进程”,在 Linux 下就是第 0号进程。
CPU的halt 指令(硬件层面的特权指令),停止所有进程运行。当调度器在没有其它进程可供调度时就开始运行空闲进程,循环中不断执行halt指令。


总结

计算机的顶层原理就存在于我们常说的基础中:操作系统、编译原理、网络、数据结构算法等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值