VXZH


  • 首页

  • 归档

  • 标签
VXZH

JDK自带工具概览

发表于 2017-04-09 | 阅读次数

在我们平常对java程序进行问题排查、性能调优时,如果没有合适的工具,很多时候会事倍功半,甚至无法继续进行下去。其实,jdk自身已经提供了很多强大的工具供我们使用。本文就对这些工具做一个概览性的描述。

开发环境:macOS Sierra 10.12.1
JDK版本

1
2
3
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

appletviewer: 用于运行并浏览applet小程序。

extcheck: 扩展检测工具,主要用于检测指定jar文件与当前已安装的Java SDK扩展之间是否存在版本冲突。

idlj: IDL转Java编译器(IDL-to-Java Compiler),用于为指定的IDL文件生成Java绑定。IDL意即接口定义语言(Interface Definition Language)。

jar: jar文件管理工具,主要用于打包压缩、解压jar文件。

jarsigner: jar密匙签名工具。

java: Java运行工具,用于运行.class字节码文件或.jar文件。

javac: Java编译工具(Java Compiler),用于编译Java源代码文件。

javadoc: Java文档工具,主要用于根据Java源代码中的注释信息生成HTML格式的API帮助文档。

javafxpackager: JavaFX包装器,用于执行与封装或签名JavaFX应用有关的任务。JDK 8u20已经迁移此工具到javapackager。

javah: Java头文件工具,用于根据Java类生成C/C++头文件和源文件(主要用于JNI开发领域)。

javap: Java反编译工具,主要用于根据Java字节码文件反汇编为Java源代码文件。

javapackager: 执行针对Java应用程序和JavaFX应用程序的打包和签名的任务。包含了javafxpackager的功能。

jcmd: Java 命令行(Java Command),用于向正在运行的JVM发送诊断命令请求。

jconsole: 图形化用户界面的监测工具,主要用于监测并显示运行于Java平台上的应用程序的性能和资源占用等信息。

jdeps: 用于分析Java class的依赖关系.

jdb: Java调试工具(Java Debugger),主要用于对Java应用进行断点调试。

jhat: Java堆分析工具(Java Heap Analysis Tool),用于分析Java堆内存中的对象信息。

jinfo: Java配置信息工具(Java Configuration Information),用于打印指定Java进程、核心文件或远程调试服务器的配置信息。

jjs: 对Nashorn引擎的调用。Nashorn是基于Java实现一个轻量级高性能的JavaScript运行环境。

jmap: Java内存映射工具(Java Memory Map),主要用于打印指定Java进程、核心文件或远程调试服务器的共享对象内存映射或堆内存细节。

jmc: Java任务控制工具(Java Mission Control),主要用于HotSpot JVM的生产时间监测、分析、诊断。开发者可以使用jmc命令来创建JMC工具。 https://docs.oracle.com/javacomponents/jmc-5-5/jmc-user-guide/toc.htm

jps: JVM进程状态工具(JVM Process Status Tool),用于显示目标系统上的HotSpot JVM的Java进程信息。

jrunscript: Java命令行脚本外壳工具(command line script shell),主要用于解释执行javascript、groovy、ruby等脚本语言。

jsadebugd: Java可用性代理调试守护进程(Java Serviceability Agent Debug Daemon),主要用于附加到指定的Java进程、核心文件,或充当一个调试服务器。

jstack: Java堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息。

jstat: JVM统计监测工具(JVM Statistics Monitoring Tool),主要用于监测并显示JVM的性能统计信息,包括gc统计信息。

jstatd: jstatd(VM jstatd Daemon)工具是一个RMI服务器应用,用于监测HotSpot JVM的创建和终止,并提供一个接口,允许远程监测工具附加到运行于本地主机的JVM上。

jvisualvm: JVM监测、故障排除、分析工具,主要以图形化界面的方式提供运行于指定虚拟机的Java应用程序的详细信息。

keytool: 密钥和证书管理工具,主要用于密钥和证书的创建、修改、删除等。主要用于获取或缓存Kerberos协议的票据授权票据。允许用户查看本地凭据缓存和密钥表中的条目(用于Kerberos协议)。Kerberos密钥表管理工具,允许用户管理存储于本地密钥表中的主要名称和服务密钥。

native2ascii: 本地编码到ASCII编码的转换器(Native-to-ASCII Converter),用于”任意受支持的字符编码”和与之对应的”ASCII编码和(或)Unicode转义”之间的相互转换。

orbd: 对象请求代理守护进程(Object Request Broker Daemon),它使客户端能够透明地定位和调用位于CORBA环境的服务器上的持久对象。

pack200: JAR文件打包压缩工具,它可以利用Java类特有的结构,对普通JAR文件进行高效压缩,以便于能够更快地进行网络传输。这是微软提供的对象包装程序,用于对象安装包。

policytool: 策略工具,用于管理用户策略文件(.java.policy)。

rmic: Java RMI 编译器,为使用JRMP或IIOP协议的远程对象生成stub、skeleton、和tie类,也用于生成OMG IDL。

rmid: Java RMI 激活系统守护进程,rmid启动激活系统守护进程,允许在虚拟机中注册或激活对象。

rmiregistry: Java 远程对象注册表,用于在当前主机的指定端口上创建并启动一个远程对象注册表。

schemagen: XML schema生成器,用于生成XML schema文件。

serialver: 序列版本命令,用于生成并返回serialVersionUID。

servertool: Java IDL 服务器工具,用于注册、取消注册、启动和终止持久化的服务器。

tnameserv: Java IDL瞬时命名服务。

unpack200: JAR文件解压工具,将一个由pack200打包的文件解压提取为JAR文件。

wsgen: XML Web Service 2.0的Java API,生成用于JAX-WS Web Service的JAX-WS便携式产物。

wsimport: XML Web Service 2.0的Java API,主要用于根据服务端发布的wsdl文件生成客户端存根及框架

xjc: 主要用于根据XML schema文件生成对应的Java类。

参考资料:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/toc.html

VXZH

JVM之Class类文件结构

发表于 2017-04-04 | 阅读次数

Java是一个跨平台的语言,而JVM是使其跨平台的基石。Java文件编译之后成为Class文件,这是因为有了它的存在,才使Java具有平台无关性。Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据,没有空隙存在。当遇到需要占用8位字节以上的空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储(大端存储Big-Endian)。

根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储,这种伪结构中只有两种数据类型:无符号数和表。

无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值,或者按照UTF-8编码构成字符串值。

表是由多个无符号数或者其它表作为数据项构成的复合数据类型,所有表都习惯性地以”_info”结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表。 它由下表所示的数据项构成。
Class文件格式

无论是无符号数还是表,当需要描述同意数据类型但数量不定的多个数据时,经常会使用一个前置的容器计数器加若干个连续的数据项的形式,这时称这一系列连续的某一类型的数据为某一类型的集合。

Class文件结构不像XML等描述语言,由于它没有任何分隔符号,所以Class文件中无论顺序还是数量,甚至于数据存储的字节序(Class文件使用的是Big-Endian)这样的细节,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变。

魔数

每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的Class文件。很多文件存储标准中都使用魔数来进行身份识别,譬如图片格式,如gif或jpeg等在文件头中都存有魔数。Class文件魔数的值为0xCAFEBABE。如果一个文件不是以0xCAFEBABE开头,那它就肯定不是Java class文件。

版本号

紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6是次版本号(Minior Version),第7个和第8个字节是主版本号(Major Version)。Java的版本号是人45开始的,JDK1.1之后的每个JDK大版本发布主版本号向上加1,高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式并未发生变化,虚拟机也必须拒绝执行超过其版本号的Class文件。JDK1.1能支持版本号为45.0~45.65535的Class文件,JDK1.2则能支持45.0~46.65535的Class文件。JDK1.7可生成的Class文件主版本号的最大值为51.0。

常量池

紧接着主次版本号之后的是常量池入口,常量池可以理解为Class文件中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时他还是在Class文件中第一个出现的表类型数据。

由于常量池中的常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数器(constant_pool_count)。与Java中语言习惯不一样的是,这个容量计数器是从1而不是从0开始的。在Class文件格式规范制定之时,设计者将第0项常量空出来是哟特殊考虑的,这个做的目的在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量”的含义,这种情况就可以把索引值置为0来表示。Class文件结构中只有常量池的容量计数是从1开始的,对于其他集合类型,包括接口索引集合、字段表集合、方法表集合等的容量计数都与一般习惯相同,从0开始。

常量池之中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、被声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括了下面三类常量:

  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符

Java代码在进行Java编译的时候,并不像C和C++那样有”连接”这一步骤,而是在虚拟机加载Class文件的时候进行动态连接。也就是说,在Class文件中不会保存各个方法和字段的最终内存布局信息,因此这些字段和方法的符号引用不经过转换的话是无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析并翻译到具体的内存地址之中。

常量池中的每一项常量都是一个表,在JDK1.7之前共有11种结构各不相同的表结构数据,在JDK1.7中为了更好地支持动态语言调用,又额外增加了3种(CONSTANT_MethodHandle_info、CONSTANT_MethodType_info、CONTANT_InvokeDynamic_info),这14种表都有一个共同的特点,就是表开始的第一位是一个u1类型的标志位(tag,取置见下表标志位),代有当前这个常量属于哪种常量类型。这14常量类型所代表的具体含义如下表所示。
常量池中的数据类型

之所以说常量池是最繁琐的数据,是因为这14中常量类型各自均有自己的结构。
常量池中的14种常量项的结构总表
常量池中的14种常量项的结构总表

访问标志

在常量池结束之后,紧接着的两个字节代表访问标志(access_flags),这个标志用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。具体的标识为以及标志的含义请见下表。
访问标志

access_flags中一共有16个标志位可以使用,当前只定义了其中8个,没有使用到的标志位要求一律为0。

类索引 父类索引 接口索引集合

类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。由于Java不允许多重继承,所以父类索引只有一个,除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。接口索引集合就是用来描述这个类实现了哪些接口,这些被实现的接口将按implements语句(所有这个Java类本身就是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口索引集合中。

类索引、父类索引和接口索引集合都按照顺序排列在访问标志后,类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class)_info的类描符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在CONSTANT_Utf8_nfo类型的常量中的全限定名字符串。

对于接口索引集合,入口的第一项是一个u2类型的数据,为接口计数器(interfaces_count),表示索引表的容量。如果该类没有实现任何接口,则该计数器为0,后面的接口索引表不再占用任何字节。

字段表集合

字段表(field_info)用于描述接口或类中声明的变量。字段(field)包括类级别变量以及实例级别变量,但不包括在方法内部声明的局部变量。

在class文件中,紧接在interfaces后面的是对在该类或者接口中所声明的字段的描述。首先是名为fields_count的计数,它是类变量和实例变量的字段的数量总和。在这个计数后面的是不同长度的field_info表的序列(fields_count指出了序列中有多少个field_info表)。只有在文件中由类或者接口声明了的字段才能在fields列表中列出。在fields列表中,不列出从超类或者父接口继承而来的字段。另一方面,fields列表可能会包含在对应的Java源文件中没有叙述的字段,这是因为Java编译器可以会在编译时向类或者接口添加字段。

在Java中,描述字段的信息有:字段的作用域、是实例变量还是类变量(static)、可变性(final)、并发可见性(volatile)、可否序列化(trasient)、字段数据类型、字段名称。这些信息中,各个修饰符都是布尔值,要么有某个修饰符,要么没有,很适合使用标志位来表示。而字段叫什么名字、字段被定义为什么数据类型,这些都是无法固定的,只能引用常量池中的常量来描述。
字段表结构

方法表

方法表和字段表很类似,Class文件存储格式中对方法的描述与字段的描述几乎采用了完全一致的方式,方法表的结构如同字段表一样,一次包括了访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)。
方法表结构

属性表

属性表(attribute_info)在前面的讲解之中已经出现过多次,在Class文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。与Class文件中其他的数据项目要求严格的顺讯、长度和内容不同,属性表集合的限制稍微宽松了一些,不再要求各个属性表具有严格顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java虚拟机运行时会忽略掉它不认识的属性。此处比较重要且复杂,留待下次补写(TODO)。

VXZH

线性表的链式存储结构

发表于 2017-03-09 | 阅读次数

线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这意味着这些数据元素可以存在内存未被占用的任何位置。在顺序结构中,每个数据元素只需要存储数据元素就可以了。而在链式结构中,除了要存储数据元素,还要存储它的后继元素的存储地址。

结点

我们把存储数据元素的的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的称为指针或链。这两部分信息组成数据元素ai的存储映像,称为结点(Node)。而由n个这样的结点组成一个链表,即为线性表的链式存储结构。当链表的每个结点只包含一个指针域时,我们称此链表为单链表。

对于线性表总得有个头有个尾,那么链表也不例外。我们用一个叫做头指针的东西指向链表的第一个结点,对单链表的存取必须从头指针开始进行。由于单链表的最后一个数据元素没有直接后继元素,则指针为空,通常用NULL或^表示。

有时,为了更加方便地对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点。结节点的数据域可以不存储任何信息。也可以存储例如表长等附加信息,头结点的指针域指向第一个结点,头指针此时指向头结点。

头指针与头节点

头指针与头结点不同,头结点即第一个结点,头指针是指向第一个结点的指针。链表中可以没有头结点,但不能没有头指针。

关于头指针:

  • 在线性表的链式存储结构中,头指针是指链表指向第一个结点的指针,若链表有头结点,则头指针就是指向链表头结点的指针。
  • 头指针具有标识作用,故常用头指针冠以链表的名字。
  • 无论链表是否为空,头指针均不为空。头指针是链表的必要元素。

关于头结点:

  • 头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。
  • 有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。
  • 首元结点也就是第一个元素的结点,它是头结点后边的第一个结点。
  • 头结点不是链表所必需的。

单链表带头结点与不带头结点的区别

单链表是一种最为基本的数据结构,常用的单链表又分为带头结点和不带头结点两种。从线性表的定义可以知道,线性表要求允许在任意位置进行插入和删除操作。所有的链表都有一个头指针head,带头结点的链表中head的数据项为空。

  • 带头结点的优点:在第一个结点处插入或删除操作与在其他处插入或删除的操作统一。
  • 不带头结点的优点:节省内存。

下面是带头结点的单链表与空表的比较图。
非空表
空表

接下来具体分析。

1.带头结点的插入操作
首先使用临时变量x记录要插入的位置的结点,之后不管要插入的结点o是插到链表头还是插到链表的其他位置都是如下语句:

1
2
3
Node x = 要插入位置的结点;
o.next = x.next;
x.next = o;

2.不带头结点的插入操作
若要插到链表的开头则

1
2
o.next = head.next;
head = o;//这里不再是head.next = x

若插到链表的其他位置则

1
2
o.next = x.next;
x.next = o;

3.带头结点的删除操作

1
2
p = 要删除结点的前继结点;
p.next = p.next.next;

4.不带头结点的删除操作
删除第一个节点时

1
head=head.next;

删除其他节点时,head的值不会改变。

1
p.next = p.next.next;

综上所述,带头节点的单链表,不论删除和插入的位置如何,不需要修改head的值,不带头结点的单链表则需要修改head的值。所以单链表 一般为带头结点的单链表 。

单链表的读取

单链表中,若想查找第index个元素,必须从头开始寻找,直到index为止。由于这个算法的时间复杂度取决于index的位置,当index=1时,不需要遍历,第一个就取出数据了。而当index=n时,需要遍历n-1次。因此最坏情况的时间复杂度为O(n)。因为单链表没有定义表长,所以不能事先知道循环多少次,因为也就不方便使用for来控制循环。其核心思想就是指针不断的后移。

1
2
3
4
5
6
7
8
9
10
11
private Node getElem(int index) {
int j = 0;
Node p = head.next;//指向第一个结点
while (j < index) {
p = p.next;
j++;
}
if (j > index)
// 没有查到,错误提示
return p;
}

单链表的插入

将结点o插入结点p的后面

1
2
o.next = p.next;
p.next = o;

单链表的删除

将结点o删除,o的直接前继为p

1
p.next = o.next;

VXZH

反射

发表于 2017-03-05 | 阅读次数

概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象(Class对象)。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

反射主要解决动态编程,即使用反射时,所有的对象生成是动态的,调用的方法也是动态的。反射可以简化开发,但是代码的可读性很低。很多主流框架都使用了反射技术,像ssh框架都采用了xml文件配置+反射技术。

注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面的属性和方法,还要求能够给类增加属性和方法,而JAVA中的反射只能获取调用,不能修改类的结构。

在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用。

获取Class对象的三种方式

要想知道获取Class对象的三种方式,首先我们应该知道如下三个阶段。
获取Class对象的三种方式

  • 源码阶段:Class类中静态方法forName(),读取配置文件。

    1
    Class clazz = Class.forName("全限定类名");
  • 字节码阶段:静态属性class。

    1
    Class clazz = 类名.class;
  • 存在对象阶段:Object类的getClass()方法。

    1
    Class clazz = 对象名.getClass();

获取

当我们想通过反射动态的调用方法、获取字段等,先拿到Class对象是首要工作,当我们获得了Class对象之后,那么这个类就对我们透明了,我们可以拿到它的一切。

通过反射获取带参构造方法

Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance(“字符串参数”,整形参数)方法创建对象。

1
2
3
Class clazz = Class.forName("io.github.vxzh.Person");
Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造
Person p = (Person) c.newInstance("张三",23);

通过反射获取成员变量

Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField(“name”)方法获取,通过set(obj, “李四”)方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值。

通过反射获取方法并调用

Class.getMethod(String, Class…) 和 Class.getDeclaredMethod(String, Class…)方法可以获取类中的指定方法,调用invoke(Object, Object…)可以调用该方法。

通过反射获取泛型、注解等

除了获取成员变量、成员方法、构造方法等常用的之外,还可以获取到泛型、注解等。

VXZH

指令是如何运行的

发表于 2017-02-27 | 阅读次数

一条指令的执行,必然会涉及到硬盘、内存、CPU三大计算机主要硬件的协同合作,在讲明它们是怎么协同合作之前,先让我们了解一下它们都是什么。

指令

计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。通俗点说就是我们写的每一行代码,最终都对计算机起到指示和命令。

硬盘

硬盘是计算机的主要存储媒介,它可以在计算机断电的情况下存储数据。正是因为这个特点,我们的工作结果才得以保存起来。硬盘有机械硬盘(HDD)、固态硬盘(SSD)、混合硬盘,机械硬盘是传统硬盘,而固态硬盘由于读写速度都要比传统硬盘快,现在越来越受用户青睐。

内存

计算机运行的所有程序,都是在内存中完成的。它是与CPU之间沟通的桥梁。内存(Memory)也被称为主存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。

CPU

CPU,又称中央处理器(Central Processing Unit),是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。中央处理器主要包括运算器(算术逻辑运算单元,ALU,Arithmetic Logic Unit)和高速缓冲存储器(Cache)及实现它们之间联系的数据(Data)、控制及状态的总线(Bus)。它与内部存储器(Memory)和输入/输出(I/O)设备合称为电子计算机三大核心部件。

现在我们了解了它们各自是什么,那么接下来我们聊一聊它们是怎么一起协调工作执行一条指令的。首先,请看下图,是一台计算机的硬件系统的主要部件(IO设备等没在此图展现)。

计算机硬件系统组成

我们写好的程序(如.java),原文件及编译后生成的字节码文件(.class),都会以二进制的形式存储在硬盘上。当我们想运行这个程序的时候,首先会将字节码文件经过IO总线、内存总线加载到内存中,等待CPU的调用。前面我们说过,CPU包括逻辑运算单元和寄存器(缓存等暂且不讨论),逻辑运算单元当然就是完成各种计算的任务了,而寄存器则用来暂存。它会将从内存读取的数据、指令、地址暂存起来,等待逻辑运算单元进行计算。

逻辑运算单元计算的结果,会暂存在寄存器中,之后写回内存。最后我们可以选择将结果打印到屏幕上,还是写入硬盘永久保存起来。

VXZH

VXZH

Later Equals Never.

5 日志
2 标签
© 2017 VXZH
由 Hexo 强力驱动
主题 - NexT.Mist