CSAPP-----计算机系统漫游

本章目录:

1、信息就是位+上下文

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

3、了解编译系统如何工作好处

4、处理器读并解释储存在内存中的指令

5、高速缓存至关重要

6、存储设备形成层次结构        

7、操作系统管理硬件

8、系统之间利用网络通信

9、重要主题

 


本系列文章的观点和图片均来自《深入理解计算机系统第3版》仅作为学习使用

1、信息就是位+上下文

         系统中所有的信息,包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的,区分不同数据对象的唯一方法就是我们读到这些数据对象时的上下文。

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

        为了在系统上运行hello.c的程序,每条c语句都必须被其它程序转化为一系列的低级机器语言指令。然后这些指令按照一种可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来,目标程序也成为可执行目标文件。

        在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:gcc -o hello hello.c,在这里GCC编译器驱动程序读取hello.c并把它翻译成一个可执行的目标文件hello。这个翻译过程可以分为四个阶段完成,如下图所示,执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统。

        

        *预处理阶段。预处理器(cpp)根据字符#开头的命令,修改原始的C程序,比如#include<stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入到程序文本中,这样就得到了另外一个C程序,一般会是以.i作为文件扩展名。

       *编译阶段。编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序,汇编程序包含函数main的定义,汇编语言为不同的高级语言的不同编译器提供了通用的输出语言。

        *汇编阶段。接下来汇编器将hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在文件hello.o中。hello.o文件是一个二进制文件,它包含17个字节是函数main的指令编码。

        *链接阶段。注意hello程序(简单的c语言hello,world程序)调用了printf函数,它是每个C编译器都提供的标准C库中的一个函数,printf函数存在于一个printf.o的单独的预编译好了的目标文件中,这个文件必须以某种方式合并到我们的hello程序中,链接器(ld)就负责处理这种合并,结果就得到hello文件,他是一个可执行目标文件,可以被加载到内存中,由系统执行。

3、了解编译系统如何工作好处

        *优化程序性能

        *理解连接时出现的错误

         *避免安全漏洞

4、处理器读并解释储存在内存中的指令

         此时hello.c源程序已经被编译系统翻译成了可执行文件hello,并存放在磁盘上,那么运行此文件,需要将他的文件名输入到shell中:linux>./hello之后会出现结果,./代表当前目录,shell是一个命令行解释器,他输出一个提示符,等待输入一个命令行,然后去执行这个命令,如果该命令行的第一个单词不是一个内置的shell命令,那么shell就会假设这是一个可执行文件的名字,会加载并运行这个文件。

        4.1 系统的硬件组成(和之前嵌入式很多东西是相通的)

            1.总线

                贯穿整个系统的一组电子管道,称为总线。它携带着信息字节并负责在各个部件之间传递。通常总线被设计成传送定长的字节块,也就是字(word)。字中的字节数是一个基本的系统参数,各个系统不同,现在大多机器要么是4个字节(32)位,要么是8个字节(64位)。

            2.I/O设备

                I/O设备是系统与外部世界的联系通道,一般包括鼠标、键盘、显示器以及磁盘等。

           3、主存

              主存是一个临时存储设备,在处理器执行程序是,用来存放程序和程序处理的数据。从物理上来说主存是由一组动态随机存储器(DRAM)芯片组成。

            4、处理器

                中央处理单元(CPU),简称处理器,是解释或执行存储在主存中指令的引擎,处理器的核心是一个大小为一个字的存储设备(寄存器)称为程序计数器(PC)。在任何时候,PC都指向主存中某条机器语言指令,从系统上电开始,直到断电,处理器一直在不断执行程序计数器指向的指令再更新程序计数器使其指向下一条指令。指令集的架构决定了指令执行的模型,指令主要围绕着主存、寄存器文件和算术逻辑单元进行。常见的指令操作(以嵌入式RISC指令集为例)有加载(LDR,从主存复制一个字节或一个字到寄存器)、存储(STR,从寄存器复制一个字节或字到主存的某个位置)、操作(ADD)、跳转。(https://blog.csdn.net/zl6481033/article/details/84779031)可以参考。

        4.2 运行hello程序

        整个过程:首先shell程序执行它的指令,等待我们输入一个命令,当输入字符串“./hello”后,shell程序将字符逐一读入寄存器,再把它放到内存中,如下图

            当敲回车键时,shell直到我们结束了命令的输入,然后shell执行一系列指令来加载可执行的hello文件,这些指令会将hello目标文件中的代码和数据从磁盘复制到主存,数据包括最终输出的字符串“hello,world”。利用直接存储器读取(DMA)技术,数据可以不通过处理器而直接从磁盘到达主存。一旦目标文件代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令,这些指令将"hello,world"字符串中的字节从主存复制到寄存器文件,在从寄存器文件复制到显示设备,最终显示在屏幕上。

5、高速缓存至关重要

        上面的例子揭示了一个重要问题,也就是系统花费了大量的时间把信息从一个地方挪到另一个地方。从磁盘复制到主存,从主存复制到处理器。这些操作都是开销,减慢了程序真正的工作,因此系统设计这一个主要目标就是是这些复制操作尽快完成。较大的存储设备要比较小的存储设备运行的慢,快速设备的造假远高于同类的低俗设备,比如,一个系统上,磁盘驱动器可能比主存大1000倍,但是对于处理器而言,从磁盘驱动器上读取一个字的时间要比从主存上读取开销大1000万倍。而一个典型的寄存器文件只存储几百字节的信息,但主存中却可以存放几十亿字节,然而处理器从寄存器文件中读取数据比从主存中读取要快100倍。这种差距还在持续增大,加快处理器的运行速度要比加快主存的运行速度要容易和便宜的多。针对这种差异,选取了更小更快的存储设备,成为高速缓存存储器(cache memory)作为暂时的集结区域,用来存放处理器近期可能会用到的信息。如下图

    

        位于处理器芯片上的L1高速缓存,容量可达数万字节,访问速度几乎和寄存器文件一样,一个容量为数十万到数百万字节更大的L2高速缓存通过一条特殊的总线连接到处理器,L1和L2高速缓存是用一种叫作静态随机访问存储器(SRAM)的硬件技术实现的,大部分内存操作都能在快速的高速缓存中完成。

6、存储设备形成层次结构        

        每个计算机系统中存储设备都被组织成一个存储器层次结构。如下图,从上至下,设备访问速度越来越慢,容量越来越大,每字节造价越来越便宜。

        存储器层次结构的主要思想是,上一层存储器作为低一层的高速缓存,可以运用不同的高速缓存的知识来提高程序性能。

7、操作系统管理硬件

        回到之前hello程序的例子,当shell加载和运行hello程序时,以及hello程序输出自己的消息时,shell和hello都没有直接访问键盘、显示器、磁盘或者主存,取而代之的是他们通过操作系统提供的服务,操作系统可以理解为应用程序和硬件之间插入的一层软件,所有应用程序对硬件操作都必须通过操作系统。如下图:

        

        操作系统有两个基本功能:(1)防止硬件被时空的应用程序滥用;(2)像应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。操作系统通过几个基本的抽象概念(进程、虚拟内存、文件)来实现这两个功能,如下图。

     

        文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。

    7.1 进程

         程序看上去是独占的使用处理器,主存和IO设备,处理器看上去像是在不间断地一条接一条的执行程序中的指令,也就是说程序的代码和数据是系统内存中唯一的对象。这些假象是通过进程的概念实现的。

        进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程而每个进程都好像在独占的使用硬件。而并发运行是说一个进程的指令和另一个进程的指令是交错执行的。在大多数系统中,需要运行的进程数是多于可以运行他们的CPU个数的。传统系统在一个时刻只执行一个程序,而先进的多核处理器同时能够执行多个程序,无论是单核还是多核系统中,一个CPU看上去都是在并发的执行多个进程,这是通过处理器在进程间切换实现的,操作系统实现这种交错执行的机制称为上下文切换。

       操作系统保持根据进程运行所需的所有状态信息,这种状态也就是上下文,包括很多信息,比如PC和寄存器文件的当前值,以及主存内容。任何一个时刻单处理器系统都只能执行一个进程的代码,当操作系统决定要把控制权从当前进程转移到某个新的进程时,就会进行上下文切换,也就是保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递给新进程。新进程就会从上次停止的地方开始。如上我们的例子,有两个并发的进程,shell进程和hello进程,他们的切换时如下图:

    

          从一个进程到另一个进程的转换时由操作系统内核(kernel)管理的,内核式操作系统代码常驻贮存的部分,当应用程序需要操作系统的某些操作时,比如读写文件,它会执行一条特殊的系统调用指令,将控制权传递给内核,然后内核执行被请求的操作并返回应用程序。内核不是一个独立的进程,相反它是系统管理全部进程所用代码和数据结构的集合。

    7.2 线程 

         通常我们认为一个进程只有一个单一的控制流,但是在现代操作系统中,一个进程实际上可以由多个称为现成的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。线程也成为越来越重要的编程模型,因为多线程之间比多进程更容易共享数据,线程一般都比进程更高效。

    7.3 虚拟内存

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

        

         *程序代码和数据:对所有进程来说,代码是从同一固定地址开始,紧接着是全局变量相对应的数据位置,代码和数据区都是按照可执行文件的内容初始化的。

        *堆 :代码和数据区后紧随的是运行时堆。

        *共享库:在地址空间中间一部分是用来存放像C标准库和数学库这样的共享库的代码和数据的区域。

        *栈:位于用户虚拟地址空间顶部的就是用户栈,编译器用它来实现函数调用。

        *内核虚拟内存:地址空间顶部的区域为内核保留,不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。

    7.4 文件

       文件就是字节序列,仅此而已。系统中所有输入和输出都是用过系统I/O系统函数调用读写文件来实现的。

8、系统之间利用网络通信

        现代系统经常是通过网络与其他系统连接到一起,从一个系统来看,网络可视为一个I/O设备,当系统从主存中复制一串字节到网络适配器,数据流经过网络到达另一台机器,从一台主机复制信息到另外一台已经成为计算机系统最重要的用途之一。电子邮件、即时通信、万维网、FTP、这样的应用都是基于网络复制信息的功能。

9、重要主题

    9.1 Amdahl定律

        该定律的主要思想是,当我们对系统的某个部分进行加速时,其对系统整体性能的影响却决于该部分的重要性和加速程度。

    9.2 并发与并行

        两个需求:一个是想要计算机做得更多,一个是想要计算机运行得更快。并发是一个通用的概念,指一个同时具有多个活动的系统,并行指用并发来使一个系统运行得更快。按照系统层次结构中由高到低得顺序重点强调三个层次。

        1.线程级并发 2.指令级并发 3.单指令、多数据并行

    9.3 计算机系统中抽象的重要性

        抽象的使用是计算机科学中最重要的概念之一。指令集架构提供了对实际处理器硬件的抽象,文件是对I/O设备的抽象,虚拟内存是对程序存储器的抽象,进程是对一个正在运行的程序的抽象。虚拟机,提供了对整个计算机的抽象。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值