《深入理解计算机系统》学习记录

第一章:计算机系统漫游

#include<stdio.h>

int main()
{
    
    
	printf("hello,world\n");
	return 0;
}

1 信息就是位+上下文

  • 系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特(0和1)表示的。区分不同数据对象的唯一方法就是我们读到这些写数据对象时的上下文。比如在不同程序中,同一个字节序列可能表示一个整数、浮点数、字符串或者机器指令

2 程序被翻译成不同的格式

在这里插入图片描述

  • 预处理阶段: 预处理器(cpp)根据以字符#开头,修改原始的c程序。例如,hello.c中第一行#include<stdio.h>命令就钙素预处理器读取系统头文件stdio.h中的内容,并把它直接插入程序文本中。结果就得到了另一个C程序,通常是以.i作为文件扩展名
  • 编译阶段: 编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含了一个汇编语言程序。改程序包含main函数的定义
  • 汇编阶段: 汇编器(as)将hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o(二进制文件)中
  • 连接阶段: 注意hello程序调用了printf函数。printf函数存在于一个名为printf.o的单独预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器(ld)就负责处理这种合并。结果就得到了一个hello文件,他是一个可执行文件,可以被加载到内存中,由系统执行

3了解编译系统如何工作是大有益处的

  • 优化程序性能
  • 理解连接时出现的错误
  • 避免安全漏洞

4系统硬件的组成

在Unix系统上,从源文件到目标文件的转化是由编译器驱动完成的

linux> gcc-o hello hello.c

这个过程大致可以分为四个阶段,执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统。gcc编译器是Linux系统默认的编译器。

  1. 总线: 贯穿整个系统的是一组电子管,称作总线。通常总线被设计成传送定长的字节块,也就是字。但是这个字在各个系统中的设置一般也不相同。
    在这里插入图片描述
  2. I/O设备: 每个I/O设备都通过控制器或者适配器与I/O总线相连。控制器是I/O设备本身或者系统的主印制电路板(主板)上的芯片组,而适配器是一块插在主板插槽上的卡。
  3. 主存: 主存是一个临时存储设备,用来存放程序和程序处理的数据。主存是由一组动态随机存取存储器(DRAM)芯片组成的。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有唯一的地址(数组索引),这些地址是从零开始的。
  4. 处理器: 也就是CPU。处理器的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器(PC).在任何时刻,PC都指向主存中的某条机器语言命令(含有该条指令的地址)。处理器一直不断地执行PC指向的指令,再更新PC,使其指向下一条指令。处理器中还有寄存器和ALU,寄存器是小的存储设备,每个寄存器都有唯一的名字;ALU是算数逻辑单元,用来计算新的数据和地址值。

5运行hello程序

  1. shell程序字符逐一读入寄存器,再把它放入内存中(图片)
  2. 一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序的机器语言指令
  3. 这些指令将“hello,world\n”字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。

6高速缓存至关重要

随着半导体基础的进步,处理器与主存之间读取数据的差距在不断变大,为了解决这个问题,出现了高速缓冲存储器(cache) ,作为暂时的集结区域,存放处理器近期可能会需要的信息。
在这里插入图片描述

L1高速缓存位于处理器芯片上,容量可以达到数万字节,访问速度几乎可以和访问寄存器文件一样快。
L2高速缓存通过一条特殊的总线连接到处理器,容量为数十万字节到数百万字节,进程访问L2高速缓存的时间要比访问L1的时间长5倍。L1和L2都是用一种静态随机访问存储器(SRAM) 实现的

7存储设备形成层次结构

存储器层次结构的主要思想就是上一层的存储器作为低一层存储器的高速缓存
在这里插入图片描述

8操作系统管理硬件

我们可以把操作系统看成是应用程序和硬件之间插入的一层软件,所有应用程序对硬件的操作尝试都必须通过操作系统在这里插入图片描述

操作系统有两个功能:(1)防止硬件被失控的程序滥用;(2)向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备
操作系统提供了几个基本的抽象概念来实现这两个功能:进程,虚拟内存和文件
在这里插入图片描述

  • 进程: 进程是操作系统对一个正在运行的程序的一种抽象,一个系统可以同时运行多个进程,而每个进程都好像在独占地使用硬件。而并发运行则是说一个进程的指令和另一个进程的指令是交错执行的。
    操作系统保持跟踪进程运行所需要的所有状态信息。这种状态,也就是上下文。在任何一个时刻,单处理器系统都只能执行一个进程的代码。当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换(保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程),新进程就会从它上次停止的地方开始
    在这里插入图片描述

  • 线程: 一个进程实际上由多个称为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。

  • 虚拟内存: 虚拟内存是一个抽象概念,它为每一个进程提供了一个假象,即每个进程都在独占地使用主存。每个进程看到的内存都是一致的,称为虚拟地址空间 ,下图是Linux进程的虚拟地址空间(地址从下往上是增大的)
    在这里插入图片描述
    在Linux中,地址空间最上面的区域是保留给操作系统中代码和数据的,这对所有进程来说都是一样的。地址空间的底部区域存放的是用户进程定义的代码和数据

    1、程序代码和数据: 对所有进程来说,代码是从同一固定地址开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的
    2、堆: 代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始就被指定了大小,与此不同,当调用想malloc和free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。
    3、栈: 位于用户虚拟地址空间顶部的是栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地收缩和扩展,特别的,每当我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩
    4、内核虚拟内存: 地址空间顶部的区域是为内核保留的。不允许应用程序来读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作

    9文件

    文件就是字节序列,仅此而已,每个I/O设备都可以看做一个文件。

    10并发和并行

    - 线程级并发: 构建在进程这个抽象之上,我们能够设计出同时有多个程序执行的系统,这就导致了并发。使用线程,我们甚至能够在一个进程中执行多个控制流。当构建一个有单操作系统内核控制的多处理器组成的系统时,我们就得到了一个多处理器系统
    在这里插入图片描述
    微处理器芯片有4个CPU核,每个核都有自己的L1和L2高速缓存,其中的L1分为两个部分——一个保存最近取到的指令,另一个存放数据。这些核共享更高层次的高速缓存,以及到主存的接口。
    在这里插入图片描述
    超线程,有时称为同时多线程,是一项允许一个CPU执行多个控制流的技术。常规的处理器需要大约20000个时钟周期做不同线程间的转换,而超线程的处理器可以在单个周期的基础上决定要执行哪一个线程。

    - 指令级并行: 在较低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级并行。如果处理器可以达到比一个周一一条指令更快的执行速率,就称之为超标量处理器,大多数现代处理器都支持超标量操作
    ## 单指令,多数据并行: 在最低层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并行执行的操作,这种方式成为单指令,多数据,即SIMD并行。 提供这些SIMD指令多是为了提高处理影像、声音和视频数据应用的执行速度。

猜你喜欢

转载自blog.csdn.net/qq_51208748/article/details/108876657