源程序实际上就是由一个值0和1组成的位(bit)序列,8个位被组织成一组,称为字节.每个字节表示程序中某个文本字符.
大部分现代系统都是有ASCII标准表示文本字符,只由ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件.
系统中所有的信息—–包括磁盘文件、存储器中的程序、存储器中存放的用户数据以及网络上传送的数据,都是由一串位表示的.区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文.比如:在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令.
此例子为书中所写的hello.c的例子,从其生命周期分析系统的执行过程(可见原书)
在Unix系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
unix>gcc -o hello hello.c
执行这四个阶段的程序(预处理器、编译器、汇编器、链接器)一起构成了编译系统(compilation system).
1,预处理阶段.预处理器(cpp)根据以字符#开头,修改原始的C程序.
2,编译阶段.编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序.
3,链接阶段.目标文件合并到我们的hello.o程序中,链接器就处理这种合并.得到hello文件,一个可执行目标文件,可以被加载到内存中,由系统执行.
有一些重要的原因是促使程序员必须知道编译系统是如何工作的,其原因如下:
- 优化程序性能:现代编译器都是成熟的工具,通常可以生成很好的代码.但是,为了在C程序中做出好的编码选择.我们确实需要了解一些机器代码以及编译器将不同的C语句转化为机器代码的方式.例如:while循环比for循环更有效吗?
- 理解链接时出现的错误.一些最令人困扰的程序错误往往都与链接器操作有关.例如:为什么有些链接错误直到运行时才会出现?
- 避免安全漏洞.缓冲区溢出错误是造成大多数网络和Internet服务器上安全漏洞的主要原因.学习安全的第一步就是理解数据和控制信息存储在程序栈上的方式会引起的后果.
要想Unix系统上运行该可执行文件,我们将它的文件名输入到成为外壳(shell)的应用程序中.
外壳是一个命令解释器,它输出一个提示符,等待你输入一个命令行,然后执行这个命令.
- 总线贯穿整个系统的是一组电子管道,称做总线,它携带信息字节并负责在各个部件间传递.
- I/O设备:输入/输出(I/O)设备是系统与外部世界的联系通道.
- 主存:主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据.
- 处理器:中央处理单元(CPU),简称处理器,是解释(或执行)存储在主存中指令的引擎.处理器的核心是一个字长的存储设备(或寄存器),称为程序计数器(PC).
- 1,外壳程序将字符逐一读入寄存器,再把它存放到存储器中.
- 2,外壳执行一系列指令来加载可执行的文件,将目标文件中的代码和数据从磁盘复制到主存.
- 3,目标文件中的代码和数据被加载到主存,处理器开始执行程序的main程序中的机器语言指令.这些指令将字符串的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上.
Tips:
1,程序的机器指令最初是存放在磁盘上,当程序加载时,它被复制到主存.
2,指令又从主存复制到处理器.
3,数据初始时在磁盘上,然后复制到主存,最后从主存复制到显示设备.
4,较大的存储设备要比较小的存储设备运行的慢.
5,加快处理器的运行速度要比加快主存的运行速度要容易和便宜.
- 为了解决处理器与主存之间的差异,系统设计采用了更小、更快的存储设备.(高速缓存)作为暂时的集结区域,用来存放处理器近期可能会需要的信息.
- 高速缓存的容量达到数万字节,访问速度几乎和访问寄存器文件一样快.
- 程序具有访问局部区域里的数据和代码的趋势.
- 利用高速缓存可以将程序的性能提高一个数量级.
在处理器和一个又大又慢的设备之间插入一个更小更快的存储设备(高速缓存)的想法已经成为了一个普遍的观念.
计算机系统中的存储设备都被组织成了一个存储器层次结构.
可以利用对整个存储层次结构的理解来提高程序性能.
存储器层次结构的主要思想是一层上的存储器作为低一层存储器的高速缓存.
1,可以把操作系统看成是应用程序和硬件之间插入的一层软件.
2,所有应用程序对硬件的操作尝试都必须通过操作系统.
3,操作系统的两个基本功能:
- 防止硬件被失控的应用程序滥用
- 向应用程序提供简单一致的机制来控制复杂而又大相径庭的低级硬件设备.
4,操作系统的抽象概念:
- 文件是对I/O设备的抽象表示.
- 虚拟存储器是对主存和磁盘I/O设备的抽象表示.
- 进程则是对处理器、主存和I/O设备的抽象表示.
进程是计算机科学中最重要和最成功的概念之一.
进程是操作系统对一个正在运行的程序的抽象表示.
并发运行时说一个进程的指令和另一个进程的指令是交错执行的.
并发地执行多个进程,是通过处理器在进程间切换来实现的.
操作系统实现这种交错执行的机制成为上下文切换.
操作系统保持跟踪进程运行所需的所有状态信息.这种状态,就是上下文,它包括许多信息(寄存器文件当前的值,主存的内容).
一个进程实际上可以由多个称为线程的执行单元组成.
每个线程都运行在进程的上下文中,并共享同样的代码和全局数据.
多线程之间更容易共享数据.
线程一般来说比进程更高效.
多处理器时,多线程也是使程序更快运行的方法.
虚拟存储器是一个抽象概念,它为每个进程提供了一个假象.即每个进程都独享主存.
每个进程看到的一致的存储器,称为虚拟空间地址.
- 空间地址上面是为操作系统中的代码和数据保留的.对所有程序都是一样的.
- 地址空间的底部区域存放用户进程定义的代码和数据.
每个进程看到的虚拟空间地址由大量的标准定义的区构成.每个区都有专门的功能
- 程序代码和数据:对所有进程来说,代码是从同一个固定地址开始的,紧接着是C全局变量相对的数据位置.(代码和数据区在程序一开始运行就被规定了固定大小)
- 堆:代码和数据区后紧随着的是运行时堆.堆可以在运行时动态的扩展和收缩.
- 共享库:大约在地址空间的中部,一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域.
- 栈:位于用户虚拟地址空间顶部的用户栈.编译器用它来调用函数.栈在程序执行的过程中可以动态的扩展和收缩.
- 内核虚拟存储器:内核总是驻留在内存中,是操作系统的一部分.地址空间的顶部区域是为内核保留的.其他应用程序不允许读写此区域的内容或者调用内核代码定义的函数.
虚拟存储器的运作需要硬件和软件之间复杂精密的交互.包括对处理器生成的每个地址的硬盘翻译.其基本思想是把一个进程虚拟存储器的内容存储在磁盘上,然后用主存作为磁盘的高速缓存.
文件就是字节序列,仅此而已.
系统中的所有输入输出都是通过使用一小组称为Unix I/O的系统函数调用读写文件来实现的.
文件向应用程序提供了一个统一的视角,来看待系统中各种I/O设备.
如果系统视为一个孤立的硬件和软件的集合体,那么网络可以视为一个I/O设备.
当系统从主存将一串字符串复制到网络适配器时,数据流经过网络达到另一台机器上.
系统可以读取从其他机器发送来的数据,并将数据复制到自己的主存.
系统是硬件和软件互相交织的集合体,它们必须共同协作以达到运行应用程序的最终目的.
计算机的历史中,两个需求是驱动技术进步的动力.
- 希望计算机做的更多
- 希望计算机做的更快
并发是一个通用的概念,指一个同时具有多个活动的系统.
并行指的是用并发使一个系统运行的更快.并行可以在计算机系统的多个抽象层次上运行.
同时执行多个程序的系统,就导致了并发.
通过使计算机在它正在执行的程序之间快速的切换的方式来实现.
并发形式允许多个用户同时与系统交互.(如多人从web页获取信息)
并发允许一个用户同时从事多个任务.(如听歌的同时看电影 - -!)
在较低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级并行.
在最低层次上,许多现代处理器用户特殊的硬件,允许一条指令生产多个可以并行执行的操作,这种方式称为单指令、多数据,即SIMD并行.
抽象的使用是计算机科学中最为重要的概念之一.
只要执行模型一样,不同的处理器实现也能执行同样的机器代码,而又提供不同的开销和性能.
操作系统中的抽象 :
1,文件是对I/O的抽象
2,虚拟存储器是对程序存储器的抽象.
3,进程是对一个正在运行的程序的抽象.
4,虚拟机,它提供对整个计算机(操作系统,处理器和程序)的抽象.
计算机系统是由硬件和软件组成的,它们共同协作以运行应用程序.
计算机的内部的信息被表示为一组组的位,它们依据不同的上下文有不同的解释方式.
程序被其他程序翻译成不同的形式.开始时时ASCII文本,然后被编译器和链接器翻译成二进制可执行文件.
通过对计算机系统的整体了解,更深的认识到系统的运行机制,更有利于个人对整个系统的一种整体感觉,真正的去从设计系统的角度看待整个系统的运行方式,从而可以更加清晰的明白程序是如何在系统中运行的,以前很多想不明白的地方也有了新的认识.
系统介于软件与硬件之间,通过软件与硬件的相互交互来运行应用程序.而每个环节又分为各种层次,从而更好的提供上层抽象,同时在学习的过程中,体会到系统设计的精妙之处,大道至简,了解其实质的运行机制,才能更好的写出好的程序.
通过学习与记录,可以更好的去了解系统的真正面目,才能为以后的深入学习提供打下基础,温故而知新,每次读都有新的认识,有种豁然开朗的感觉.踏实学习,点滴记录.不期速成,日拱一卒….