序言
虽然自己是计算机科学与技术专业的学生,但本科并没有开设计算机组成原理这门课。也后悔本科没有多学一些东西。现在有些时候在学一些高级语言时碰到一些瓶颈,感觉有些地方吃不透。如Java语言和Go语言的内存管理,Java的堆区分为新生代和老年代,因为对象不同采用不同的垃圾回收算法(标记复制、标记清除算法),Go语言的arena区也是会full GC(标记清除算法),Go里当某个对象的指针被多个方法或线程引用时,这个指针会发生“逃逸”,逃逸后的局部变量会从栈内存分配到堆内存?它们的实际内存地址在计算机中到底是什么样的?
Go里有逃逸分析,其实Java也有,在《深入理解Java虚拟机JVM:高级特性与最佳实践》一书中,程序编译与代码优化部分中也讲到逃逸分析是Java虚拟机中比较前沿的优化技术,类似于继承关系分析一样,并不是直接优化代码的手段,而是为其他优化手段提供依据的分析技术。下面拿一小节记录一下这块内容。
逃逸分析(Escape Analysis)
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。
如果能证明一个对象不会逃逸到方法或线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,则可能为这个变量进行一些高效的优化,如下:
- 栈上分配(Stack Allocation):Java堆中的对象对于各个线程都是共享和可见的,只要持有这个对象的引用,就可以访问堆中存储的数据对象。如果确定一个对象不会逃逸方法之外,那让这个对象在栈上分配内存是一个不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,不会逃逸的局部对象所占比例很大,如果使用栈上分配,那么对象就会随方法的结束而自动销毁,垃圾收集系统的压力将会小很多。
- 同步消除(Synchronization Elimination):线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以消除掉。这种优化策略有点类似StringBuffer类的append方法在被单线程调用时进行锁消除优化。
- 标量替换(Scalar Replacement):标量(Scalar)是一个数据已经无法再分解成更小的数据表示(eg:int、long、reference类型等),如果一个数据可以继续分解,那它就称作聚合量(Aggregate),Java中的对象就是最典型的聚合量。如果把一个Java对象拆散,根据程序访问的情况,将其使用到的成员变量恢复原始类型来访问就叫标量替换。将对象拆分后,除了可以让对象的成员变量在栈上(栈上存储的数据,有很大的概率会被虚拟机分配至物理机器的高速存储器中存储)分配和读写之外,还可以为后续进一步的优化手段创建条件。
JDK1.6才实现了逃逸分析,到目前这项优化尚未成熟,主要原因是不能保证逃逸分析的性能收益必定高于它的消耗。默认不开启逃逸分析,如果有需要可以使用参数 -XX: +DoEscapeAnalysis来手动开启逃逸分析,开启之后可以通过参数 -XX:+PrintEscapeAnalysis来查看分析结果。有了逃逸分析支持之后,用户可以使用参数 -XX:+EliminateAllocations来开启标量替换,使用 -XX:+EliminateLocks来开启同步消除,使用参数 -XX:+PrintEliminateAllocations来查看标量的替换情况。
我们去JDK官网看一下最新版本的是否支持逃逸分析,可以看到在Java SE 6u23版本之后都是支持且启用的:https://docs.oracle.com/en/java/javase/16/vm/java-hotspot-virtual-machine-performance-enhancements.html#GUID-6BD8FCB5-995B-4AE9-BFAA-B2C7DE2BA5CD
计算机层次结构
机器语言是01010101100... ...这样的,对于程序猿来说识别度太高,维护及其复杂。汇编也一样。使用高级语言维护起来,识别起来更加容易。
计算机层次结构如下图,本质上程序也是从高级语言(High Level Language Program)——>汇编语言(Assembly Language Program)——>机器语言(Machine Language Program(MIPS,Million Instructions Per Second))——>控制信号规格(Control Signal Specification),高级语言通过编译器编译成汇编语言,汇编语言汇编成机器语言。
高级语言
高级语言又称为算法语言,它的实现思路,不是过分地“靠拢”计算机硬件的指令系统,而是着重面向人员能够方便地写出处理问题和解题过程的程序,力争使程序设计工作的效率更高。
目前常用的高级语言有Basic、Pascal、C++、Java、Prolog、Go等许多种。用这些语言设计出来的程序,需要经过编译程序先翻译成机器语言程序,才能在计算机的硬件系统上予以执行,个别的选用解释执行方案。
特点:
- 通用性好
- 移植性强
汇编语言
汇编语言是对计算机机器语言进行符号化处理的结果,再增加一些为方便程序设计而实现的扩展功能。
在汇编语言中,可以用英文单词或其缩写替代二进制的指令代码,更容易记忆和理解;还可以选用英文单词来表示程序中的数据(常量、变量和语句标号),使程序员不必亲自为这些数据分配存储单元,而是留给汇编程序区处理,达到基本可用标准。
若在此基础上,能够在支持程序的不同结构特性(如循环和重复执行结构,子程序所用哑变元替换为真实参数)等方面提供必要的支持,使该汇编语言的实用程度更高。
机器语言
机器语言是计算机硬件能直接识别和运行的指令的集合,是二进制码组成的指令,用机器语言设计程序基本不可行。
程序的最小单元是指令,同时,指令也是计算机硬件执行程序的最小单位。
Von Neumann结构计算机
存储程序计算机:
- 程序由指令构成
- 程序功能通过指令序列描述
- 指令序列在存储器中顺序存放
顺序执行指令:
- 用PC(Program Counter)指示当前被执行的指令
- 从存储器中读出指令执行
- 指令计数器PC指向下一条指令
指令和指令系统
计算机系统由硬件和软件两大部分组成。硬件指由中央处理器、存储器以及外围设备等组成的实际装置。软件是为了使用计算机而编写的各种系统和用户的程序,程序由一个序列的计算机指令组成。
指令是计算机运行的最小的功能单元,是指挥计算机硬件运行的命令,是由多个二进制位组成的位串,是计算机硬件可以直接识别和执行的信息体。指令中应指明指令所完成的操作,并明确操作对象。
一台计算机提供的全部指令构成该计算机的指令系统。指令用于程序设计人员告知计算机执行一个最基本运算、处理功能,多条指令可以组成一个程序,完成一项预期的任务。
指令系统在计算机中的地位
可以从6个层次分析和看待计算机系统的基本组成。指令系统层处在硬件系统和软件系统之间,是硬、软件之间的接口部分,对两部分都有重要影响。
硬件系统用于实现每条指令的功能,解决指令之间的衔接关系;软件由按一定规划组织起来的许多条指令组成,完成一定的数据运算或者事物处理功能。
指令系统优劣势一个计算机系统是否成功的关键因素。
指令功能分类:
- 数据运算指令:算术运算、逻辑运算
- 数据传输指令:寄存器之间、主存/寄存器之间
- 输入/输出指令:与输入/输出端口的数据传输
- 控制指令:转移指令、子程序调用/返回
- 其他指令:停机、开/关中断、空操作、特权、置条件码
指令格式:
指令格式:指令字中操作码和操作数地址的二进制位分配方案,如下图
名词解释:
- 指令字:完整的一条指令的二进制表示。
- 指令字长:指令字中二进制代码的位数。
- 机器字长:计算机能直接处理的二进制数据的位数。
- 指令字长(字节倍数):0.5、1、2...个机器字长。
指令的结构分为定长指令字结构和变长指令字结构,即指令长度依赖于系统设计,目前计算机机器位数较宽一般采用定长指令字结构,资源不足才采用变长指令字结构。
操作码分为定长操作码和变长操作码。
寻址方式
寻址方式(又称编址方式)指的是确定本条指令的操作数地址(形式地址)及下一条要执行的指令地址的方法。
不同的计算机系统,使用数目和功能不同的寻址方式,其实现的复杂程度和运行性能各不相同。有的计算机寻址方式较少,而有些计算机采用多种寻址方式。
通常需要在指令中为每一个操作数专设一个地址字段,用来表示数据的来源或去向的地址。在指令中给出的操作数(或指令)的地址被称为形式地址,使用形式地址信息并按一定规则计算出来或读操作得到的一个数值才是数据(或指令)的实际地址。在指令的操作数地址字段,可能要指出:
- 运算器中的累加器的编号或专用寄存器名称(编号)
- 输入/输出指令中用到的I/O设备的入出端口地址
- 内存储器的一个存储单元(或一 I/O设备)的地址
评价计算机性能的指标
- 吞吐率:单位时间完成的任务数量
- 响应时间:完成任务的时间
- 衡量性能的指标:1)MIPS(Million Instructions Per Second)单字长定点指令平均执行速度;2)CPI(Cycle Per Instruction)计算机单个指令运行时间,相对概念,主要反映计算机运算能力;3)CPU time(Central Processing Unit Time)绝对时间,这段程序CPU所花费时间;4)CPU Clock(Central Processing Unit Clock)表示用了多少CPU的时钟;
- 综合测试程序(测试床)
MIPS指令系统
- MIPS,Microprocessor without interlocked piped stages,无内部互锁流水级的微处理器,RISC芯片,由John L.Hennessy设计。
- MIPS,Million Instructions Per Second,计算机性能指标之一。
THINPAD的硬件组成
- 机器字长16位
- CPU:8个通用寄存器+16位字长+PC、SP等专用寄存器
- 主存:RAM;按字编址
- I/O:与主存共享地址空间、双串口(BF00/BF01、BF02/BF03)
- 总线:双16位地址总线,双16位数据总线;独立的访问FLASH总线
THCO MIPS指令格式
操作码+操作数地址(或操作数)
R型(21条):SLL、SRL、SRA、SLLV、SRLV、SRAV、MTSP、MOVE、ADDU、SUBU、MFPC、SLT、SLTU、CMP、NEG、AND、OR、XOR、NOT、MFIH、MTIH
I型(14条):SW_RS、SW_SP、SW、LW_SP、LW、ADDIU3、ADDSP3、ADDSP、ADDIU、LI、SLTI、SLTUI、CMPI、INT
B型(5条):B、BEQZ、BNEZ、BTEQZ、BTNEZ
J型(4条):JR、JRRA、JALR、NOP
举例:
指令系统实现
存储器及I/O:不设单独的I/O指令,统一地址空间;总线连接(地址、数据)
DataPath:ALU(add、sub、and、or);PC;SP;Register files;T;RA;IH
计算机运行机制
- DataPath:完成算术和逻辑运算,通常包括其中的寄存器。
- Control:CPU的组成部分,它根据程序指令来指挥dataPath、memory以及I/O运行,共同完成程序功能。
- Memory:存放运行时程序及其所需要的数据的场所。
- Input:信息进入计算机的设备,如键盘、鼠标等。
- Output:将计算结果显示给用户的设备,如显示器、硬盘、打印机、喇叭等。
数据表示及检错纠错
·数据编码与表示:
- 需要在计算机中表示的对象:程序、整数、浮点数、字符串、逻辑值(全部通过编码表示)
- 表示方式:用数字电路的两个状态表示,存放在机器字中;由上一层的抽象计算机来识别不同的内容
- 编码原则:少量简单的基本符号;一定的规则;表示大量复杂的信息;方便使用
编码表示:
- 基本元素:0、1两个基本符号
- 字符:26字母(5位);大小写+其他符号(7bits in 8);世界上其他语言的文字(16bits unicode)
- 无符号整数:0、1、2... ...2^n-1
- 逻辑值:0 — >false; 1 —> true
- 颜色
- 位置/地址/指令
- 但n位只能代表2^n个不同的对象
未完