ch 1: 程序的生命周期

  • 1.2 把程序转化为 低级机器语言指令。然后把 指令 打包为 可执行目标程序 的格式打包, 并以二进制的磁盘文件的形式存放。目标程序也 称为可执行目标文件

  • 在Unix 系统上, 源文件到目标文件的转化是由编译器驱动程序完成的: gcc 编译器驱动程序读取源程序文件 hello.c , 并把它翻译成一个可执行目标文件 hello. 这个翻译过程分为4 个阶段完成。编译系统:hello.c (文本)
    1 预处理器 : cpp -> hello.i (文本)
    2 编译器 : ccl -> hello.s (文本)
    3 汇编器: as -> hello.o(二进制)
    4 链接器: ld -> hello (二进制 , 可执行程序)

    • 预处理阶段: (cpp)更具以字符 # 开头的命令, 修改原始的C 程序。 入去内容,并直接把 内容 插入程序文本中。 得到 hello.i
    • 编译阶段: (ccl)将文本文件 hello.i 翻译成文本文件 hello.s , 它包含一个汇编语言程序。翻译以后,低级机器语言指令以文本格式描述。汇编语言
    • 汇编阶段:(as)汇编器 将 hello.s 翻译成机器语言指令, 并把指令打包成一些种叫做 可重定位目标程序, 并将结果保存在文件 hello.o (二进制文件)中
    • 链接阶段 : hello 程序调用了printf 函数, 她是每个C 编译器都提供的的标准C 库中的一个函数。 print函数存在于一个名为 printf.o 的单独的预编译好了的目标文件中, 而这个文件必须以某种方式合并到我们的 hello.o 程序中。 链接器(Id)就负责处理这种合并。结果就得到 hello 文件, 他是一个 可执行目标文件, 可以被加载到内存中,由系统执行。
  • 1.4 处理器读并解释存储在内存中的指令

    • after hello.c 源程序已经被编译系统翻译成了可执行目标文件 hello.o, 并被存放在磁盘上。 要想在 Unix 系统上运行该可执行文件, 我们将他的文件名输入到称为 shell 的应用程序中:
linux> ./hello
hello, world
linux>

shell 是一个命令行解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果该命令行的第一个单词不是一个内置的 shell 命令, 那么shell 就会假设这是一个可执行文件的名字,它将加载并运行这个文件。 所以在此例中,shell 将加载并运行hello 程序, 然后等待程序终止。 hello 程序在屏幕上输出他的消息, 然后终止。 shell 随后输出一个提示符, 等待下一个输入的命令行。
1 总线:
2 I/O 设备:
3 主存:

  • 3.1 主存是一个临时存储设备, 在处理执行程序时,用来存放程序和程序处理的数据。从物理上来说, 主存是由一组 动态随机存储器(DRAM)芯片组成的。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址, 这些地址是从零 开始的。

4 处理器

  • 4.1 中央处理单元(CPU), 简称 处理器, 世界是存储在 主存中指令的引擎。CPU 在指令的要求下可能会执行以下操作

    • 加载 :从主存 复制内容 到 寄存器, 以覆盖寄存器原来的内容
    • 存储 : 从寄存器 复制内容 到主存的某个位置, 以覆盖这个位置上原来的内容
    • 操作:
    • 跳转:
  • 1.4.2 运行hello 程序

    • 初始时, shell 程序执行它的指令,等待我们输入一个命令。 待我们输入指令后, shell 程序将字符逐一读入寄存器,再把它存放入内存中。当我们结束命令的输入后。shell 执行一系列指令来加载 可执行的hello 文件, 这些指令将 hello 目标文件中的代码和数据从磁盘复制到主存。 磁盘 -> 主存 -> 寄存器 , 再从寄存器文件中复制到 显示设备。
  • 高速缓存至关重要

    • hello 程序的机器指令最初是存放在磁盘上,当程序加载时,他们被复制到主存; 当处理器运行时,指令又从主存复制到处理器。多次复制减慢了程序的速度。

    • 高速缓存存储器(cache memory), 加快了主存的运行速度。 cached memory 存放最近需要的信息。

    • 存储器层次结构 L0 - L6

      • L0: 寄存器
      • L1: SRAM
      • L2: SRAM
      • L3: SRAM
      • L4: 主存 (DRAM)
      • L5: 本地二级存储(本地磁盘)
      • L6: 远程二级存储 (分布式文件系统, web 服务器)
  • 1.7 操作系统管理硬件 : 我们可以把操作系统 看成是 应用程序 和 硬件之间 的一层软件。 所有引用程序对硬件的操作册灰姑娘是都必须通过操作系统。

    • 应用程序 (shell, hello) -> 软件
    • 操作系统 -> 软件
    • 处理器, 主存, I/O 设备 -> 硬件
  • 操作系统有两个基本功能:

    • (1) 防止硬件被失控的应用程序滥用
    • (2) 向应用程序提供简单一致的机制来控制 硬件设备
    • 操作系统通过这几个基本的抽象概念 (进程, 虚拟内存 和 文件 )来实现以上功能
      • 处理器 -> 进程
      • 主存 -> 虚拟内存
      • I/O 设备 -> 文件
  • 1.7.1 进程

    • 进程是操作系统对一个正在运行的程序的一种抽象。
    • 并发运行 : 一个进程的指令和另一个进程的指令是交错执行的, 操作系统实现这种交错执行机制 称为上下文切换。
    • 例子: 场景中有两个 并发的进程: shell 进程 和 hello 进程。 最开始只有 shell 进程在运行, 即等待命令行上的输入。 当我们让它运行 hello 程序时, shell 通过调用一个专门的函数, 即系统调用。 1. 操作系用保存 shell 进程的上下文,2. 创建一个新的 hello 进程及其上下文, 3. 然后将控制权转给新的 hello 进程。 hello 进程终止后, 操作系统恢复shell进程的上下文, 并将控制权传回给shell, shell 进程会继续等待下一个命令行的输入。
    • 从一个进程到另一个进程的转换是由 操作系统内核(kernel)管理的。kernel 不是一个独立的进程。 相反, 它是系统管理全部进程所用代码 和 数据结构的集合。
  • 1.7.2 线程

    • 一个进程可以运行多个线程, 每个线程 都运行在进程的上下文中, 并共享同样的代码和 全局数据。 优点: 多线程比多进程之间更容易共享数据。
  • 1.7.3 虚拟内存

    • 虚拟内存是一个抽象概念,它为每个进程提供了一个假象, 即每个进程都在独占的使用主存。
      • 程序代码和数据 : 代码和数据区是直接按照 可执行目标文件的内容初始化的
      • 堆:从下向上扩展和收缩,当调用 malloc 和 free. 代码和数据区 紧随 其后的是运行时的堆。
      • 共享库 : 用于 动态链接
      • 栈 : 编译器用它来实现函数调用。 和堆一样,在程序执行期间 会动态的扩展和收缩。当我们调用一个函数时, 栈就会增长; 从一个函数返回时, 栈就会收缩。
      • 内核虚拟内存:地址空间顶部的区域是为内核保留的。基本思想 是把一个进程虚拟内存的内容存储在磁盘上,然后用主内存作为磁盘的高速缓存。
  • 1.7.4 文件

    • 文件就是字节序列。 每个I/O 设备都可以看成文件。系统中所有输入输出都是通过使用一小组称为 Unix I/O 的系统函数调用读写文件来实现的。
  • 1.8 系统之间利用网络通信

    • 从一个单独的系统来看, 网络可视为一个 I/O 设备。当系统从主存复制一串 字节到网络适配器时, 数据流经过网络到达另一台机器。
    • 举例:
        1. 用户在键盘上 输入“hello”
      • 2.客户端向 talnet 服务器发送字符串 “hello” ;
        1. 服务器向shell 发送字符串“hello”, shell 运行hello 程序并将输出发送给 telnet 服务器。
        1. telnet 服务器向客户端 发送字符串 “hello world \n”
        1. 客户端在显示器上打印“ hello world \n” 字符串
  • 小结

你可能感兴趣的:(ch 1: 程序的生命周期)