计算机系统基础

Information is Bits in Context:
source program(source file) 是一个bit序列,只有0和1组合。
8-bit比特构成一个chunk块,称为bytes,字节。每个字节表示一些程序中文本字符。

大多数现代系统用ASCII标准来表示每文本字符,而每个字符都有唯一字节数值。
比如a,b,A等都对应着唯一的数值。

比如我们编写的 hello.c 程序,存储为一个上面字节数值序列。
每个整数对应着一些字符,

由ASCII专门字符集组成的文件,成为text file,文本文件。
其它的所有文件都是binary file。

系统中所有的信息,包括磁盘文件,内存中的程序,内存中的用户数据,网络上传输的数据都是比特块。
唯一不同的是我们通过不同的context来区分不同的数据对象,这个上下文是我们浏览它的容器。
由于我们使用的浏览上下文context的不同,同一个字节序列可以展示成整数,浮点数,字符串或者机器指令。


程序被其它的程序翻译成不同形式:
我们编写高级的C程序,是以人类能够读并理解的形式完成的。但是为了让其在操作系统上运行,
每条C语句必须转换成低级的机器语言指令串。然后将这些指令打包成一个格式叫做executable object program
并保存成二进制硬盘文件,这种对象程序也被称为executable object file,可执行对象文件。
unix 中通过GCC编译
unix gcc -o hello hello.c

命令行解释器程序会打开一个提示窗口,等待输入命令行,并执行该命令。
如果命令行的第一个单词跟shell内建的命令不符合,shell就会假设该输入是一个可执行文件名,
开始加载并运行它。

一个系统的硬件组织:
Buses 主线:
运行在整个系统中的电子导管conduit集合,我们称之为buses。
在各个组件之间交换信息字节。通常设计成交换固定大小的字节块,成为words。
一个word的大小是系统基准参数,因系统不同而不同。
比如,Intel奔腾一个word的大小是4bytes,而intel 亿腾word大小是8bytes,嵌入式控制系统
一个word的大小在1~2bytes。

I/O 终端:
输入/输出终端是系统跟外界的连接。一般有键盘,鼠标,显示器和硬盘。
硬盘用于长期存储数据和程序。
每个I/O终端都被通过controller或者adapter连接到I/O 总线上。
Controller是终端上面或者系统主板上的芯片组。
一个adapter是一个可以主板凹槽上的卡。
无论是谁都是为了在I/O主线和I/O终端之间进行信息转换的设备。

Main memory:主存储器
是一个临时存储终端,保存处理器执行的程序的数据和程序。
物理上,他是由一组Dynamic Random Access Memory(DRAM)芯片组成。
逻辑上,内存是一个字节的线性数组,每个数组都有自己唯一的从零开始的地址(数组索引)。
通常,组成程序的每个机器指令可以包含一个变量的字节数。
数据项的大小跟C编程变了类型相一致,比如一个运行Linux的Intel机器,
short需要2bytes,int,float,long需要4bytes,double则是8bytes

Processer:处理器
central processing unit(CPU),简称处理器 processor。
是解析或者执行存储在主存储器里的指令的引擎。
在其核心内部是一个word大小存储终端(或者register寄存器)称为 program counter(PC)。
在任意时刻,PC指向主内存里的机器语言指令。

随着电源启动,到电源关闭,处理器一直在重复的执行基础任务:
从PC指向的内存位置读取指令,解析指令中的比特,执行一些由指令表示的简单操作。
然后更新PC指针到下一条指令位置。

围绕着主存储只有简单的几个操作,注册表文件,和 arthmetic/logic unit(ALU)
注册表文件式一个小的存储终端,它由一些列的word大小寄存器集合组成。每一个都有自己唯一的名字。
算数运算器计算新的数据和地址值:

Load:拷贝一个字节或者一个word(字节块),覆盖寄存器以前的内容。
Store:从寄存器中拷贝一个字节或者一个word到主存储器,覆盖该位置以前的内容。
Update:从两个寄存器中拷贝内容到ALU,算数运算单元会将这两个word加在一起并将结果存储到一个寄存器。
        覆盖该寄存器以前的内容。
I/O Read:从I/O终端拷贝一个字节或者一个word到一个寄存器。
I/O Write:从寄存器中拷贝一个字节或者一个word到I/O 终端。
Jump:从指令本身提取一个word并拷贝该word到program counter(PC),覆盖PC中原有的值。

在运行程序的时候:我们的shell程序执行自己的指令,并等待我们的命令输入。
当我们键入hello后,shell程序将其读入到一个register寄存器中,然后将其保存到内存。
当我们单击回车键后,shell程序知道我们已经完成了命令输入,shell就会
通过执行从硬盘上拷贝hello对象文件的代码和数据到主存储器来加载可执行的hello文件,

使用一种叫做 direct memory access(DMA)的技术,数据直接从硬盘到主存储器,不需要经过处理器。
一旦hello对象文件的数据和代码被夹在到内存,处理器就开始执行hello程序的main程序中的机器指令。
这些指令从内存中拷贝字符串字节“hello, world\n” 到注册表文件,从这里显示到终端上。

缓存问题:
一个重要的问题在于系统会在移动信息上花费大量的时间。
一般应用程序都是保存在硬盘上,当程序加载时,它们被拷贝到主存储器(内存),在处理器运行程序时,
它们从内存中拷贝到处理器中。比如“hello,world\n"本来保存在硬盘上,它要首先被拷贝到内存,然后从内存中
显示到显示终端上。

从物理规则上看也是,大的存储终端处理慢于较小的存储终端。
一般硬盘的处理速度是内存的百分之一左右,处理器从硬盘读一个word比从内存读一个word耗时
多约100万倍。

一个传统的注册表文件只能存储几百字节的信息,而主内存则可以存储百万字节的信息。
而处理器从注册表中读数据的速度是从主内存中读取速率的100倍。

现在processor-memory gap不断的增加,就是说让处理器运行速度更快比让内存运行速度更快更容易。

为了解决处理器和内存之间的鸿沟,系统设计者们设计了更小更快的存储终端叫做 caches 缓存。
它是一个信息的临时存储区域,存储处理器可能会用到的信息。
L1缓存位于处理器芯片组里,保持上万字节内容可以提供跟寄存器类似的访问速度。
L2缓存通过一个特定的数据总线跟处理器相联,它有hundreds of thousands to million 几十万到几百万 字节
要访问L2的时间约是访问L1的5倍左右。但是仍比访问内存要快上5-10倍。
L1和L2存储都是通过硬件实现的,该技术成为Static Random Access Memory(SRAM)。


存储终端的层次体系:
在处理器和较大型较慢的主内存终端之间插入一个较小型较快的存储终端(SRAM缓存)变成了一个普遍的做法。
寄存器是L1内容的缓存,L1是L2内容的缓存,L2是主内存的缓存,内存是本地硬盘的缓存,本地硬盘是网络其它文件
系统的缓存。


操作系统对硬件的管理:
在我们运行hello world程序时,程序会直接访问键盘,显示器,硬盘和主内存。
这些访问都是在操作系统的帮助下完成的。
我们可以把操作系统看作是程序和硬件之间的中间层,程序对硬件所有的操作都是经过操作系统来完成的。
操作系统有两个主要目的,第一,保护硬件免遭失控的应用滥用。第二,为应用程序提供简单同意的机制来操作
计算和普遍的底层硬件设备的差异。

输入输出设备组成了文件系统,文件系统+内存组成了虚拟内存,处理器+虚拟内存组成了process进程。

也就是说文件从输入/输出设备抽象而来,虚拟内存是内存和硬盘输入/输出设备的抽象,
进程是处理器,主内存和输入/输出设备的抽象。

处理器:
当我们执行一个程序时,操作系统提供了一个幻觉给我们,似乎只有唯一一个程序运行在该操作系统上。
程序似乎在独占式的使用处理器,内存和I/O设备。
处理器似乎是一个接一个的执行程序里的指令,而互不打扰。程序的代码和数据似乎是系统内存里唯一的数据对象。
这些假象提供了一个概念叫做 process 进程。计算机科学里最为重要和成功的创造。

一个进程是为运行一个程序做的对操作系统的一种抽象。
在同一个系统中多个进程可以并行运行,每个进程似乎都独占使用硬件。
并行意味着一个进程的指令和另外一个进程的指令被交错执行。
操作系统执行这种交错处理是通过context switching上下文切换机制来完成的。

操作系统追踪所有需要处理器按序运行的信息的状态,这些状态称为context 上下文。
包括的内容有 当前PC值,注册文件register file,内存内容。
在任意一个时间点,有且只有一个进程运行在系统上。
当操作系统准备从当前进程将控制权转换给新的进程时,它会通过保存当前进程的上下文,
将新的进程的上下文载入,然后将控制权给新的上下文来执行一个context switch。
新的进程上下文获取控制权执行其自己的程序。


Threads:线程
一个线程具有自己独立的控制流程,同时它自身又可以由多个执行单元组成,我们称之为threads
每个运行在同一个进程中的线程可以共享代码和全局数据。

因为在网络服务中需要并行运算,线程变成越来越重要的编程模型,该模型在多个 
线程之间共享数据比在多个进程之间共享数据容易的多 。而且线程通常比进程效率更高 。

虚拟内存:
Virtual memory是提供给每个进程的一个抽象,使它有一个独占使用内存的错觉。
每个进程都有一个统一的内存视图,那就是 virtual address space虚拟地址空间 。
Linux系统中,有最多四分之一的 地址空间是为操作系统的代码和数据预留的,这些数据和代码对所有进程
都是通用的。
最低有四分之三的 地址空间是留给用户进程的数据和代码的 。
地址数是从底向顶增加的。

虚拟地址空间在每个进程看来都是由定义好的区域数量组成,每个区域都有特定的目的。
从最低地址开始:

程序代码和数据:代码从同样的固定地址开始,接着是全局C变量的数据位置。这些代码和数据区域直接从
可执行对象文件的内容中初始化。

Heap:堆,在代码和数据后面是run-time heap, 一旦进程启动后该区域大小是固定的,堆会随着我们调用C标准类库
函数malloc和free来动态的增加和缩小。


共享类库:
在虚拟地址空间的中间部分保存着shared libraries的代码和数据,比如C标准类库和数学类库。

Stack:栈,在用户虚拟地址空间的顶层是user stack,这里编译器用于实现函数调用,跟堆类似,
在程序执行过程中它也可以动态的增加和缩小。每次我们调用函数时,它就会增加,我们从函数中返回时,
它就会缩小。


Kernel virtual memory:内核虚拟内存
这里的kernel是指常驻内存的部分操作系统内容。最多有四分之一的地址空间是预留给kernel的。
应用程序时不允许直接读取这块区域的数据和定义在该区域的函数的。

关于虚拟内存的工作原理:它需要在硬件和操作系统之间进行复杂的交互,包括一个将处理器生成的地址
转换。 本质上是保存处理器的虚拟内存到硬盘,然后用内存作为硬盘的缓存。


Files:
一个Unix文件是一个字节序列。
每个I/O设备,包括硬盘,键盘,显示器,甚至网络,都被模型化为一个文件。
系统中所有的输入输出都是通过调用一些列的操作系统函数来(System call)读取和写入文件来完成的。

文件这个简洁优雅的概念,为应用程序在系统中所有各式各样的输入输出设备提供了一个统一的视图。


系统通过网络跟其它系统交互:
从单个系统的角度来说,网络可以被看作仅仅是另外一个输入/输出设备。
当一个系统从内存中拷贝一个字节序列到网络适配器是,数据流跨越网络到了另一台机器上而不是本地硬盘。
类似的,系统可以读取发自其它机器的数据并拷贝这些数据到其内存中。

邮件系统,即使消息,www,FTP以及telnet都是基于网络间信息拷贝来完成的。

我们可以采用类似telnet应用程序来远程计算机上运行helloworld,假设我们使用运行在本地的telnet客户端
来连接运行在远程机器上的telnet server,在我们登录远程机器并运行一个shell后,远程shell就会等待一个输入命令
这样运行一个helloworld需要5个步骤:
1、用户通过本地键盘键入hello
2、telnet客户端发送hello字符串到远程telnet server
3、远程机器上的telnet server发送hello字符串给 运行hello程序的shell,shell会发送输出给telnet server
4、telnet Server 发送输出字符串到telnet 客户端
5、客户端打印字符串结果到显示器

这种类型的客户端和服务端之间信息交换是所有网络应用的典型模式。
 

转载于:https://my.oschina.net/u/924064/blog/903334

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值