当前位置:首页 » 编程软件 » 编译器的分析模型包含哪些部分

编译器的分析模型包含哪些部分

发布时间: 2024-07-11 07:54:02

① 技术解析Transwarp Inceptor是怎样炼成的

技术解析Transwarp Inceptor是怎样炼成的
当前Hadoop技术蓬勃发展,用于解决大数据的分析难题的技术平台开始涌现。Spark凭借性能强劲、高度容错、调度灵活等技术优势已渐渐成为主流技术,业界大部分厂商都提供了基于Spark的技术方案和产品。根据Databricks的统计,目前有11个商业的Spark版本。
在使用Spark作出计算平台的解决方案中,有两种主流编程模型,一类是基于SparkAPI或者衍生出来的语言,另一种是基于SQL语言。SQL作为数据库领域的事实标准语言,相比较用API(如MapReceAPI,SparkAPI等)来构建大数据分析的解决方案有着先天的优势:一是产业链完善,各种报表工具、ETL工具等可以很好的对接;二是用SQL开发有更低的技术门槛;三是能够降低原有系统的迁移成本等。因此,SQL语言也渐渐成为大数据分析的主流技术标准。本文将深入解析Inceptor的架构、编程模型和编译优化技术,并提供基准测试在多平台上的性能对比数据。
1.Inceptor架构
TranswarpInceptor是基于Spark的分析引擎,如图1所示,从下往上有三层架构:最下面是存储层,包含分布式内存列式存储(TranswarpHolodesk),可建在内存或者SSD上;中间层是Spark计算引擎层,星环做了大量的改进保证引擎有超强的性能和高度的健壮性;最上层包括一个完整的SQL99和PL/SQL编译器、统计算法库和机器学习算法库,提供完整的R语言访问接口。
TranswarpInceptor可以分析存储在HDFS、HBase或者TranswarpHolodesk分布式缓存中的数据,可以处理的数据量从GB到数十TB,即使数据源或者中间结果的大小远大于内存容量也可高效处理。另外TranswarpInceptor通过改进Spark和YARN的组合,提高了Spark的可管理性。同时星环不仅仅是将Spark作为一个缺省计算引擎,也重写了SQL编译器,提供更加完整的SQL支持。
同时,TranswarpInceptor还通过改进Spark使之更好地与HBase融合,可以为HBase提供完整的SQL支持,包括批量SQL统计、OLAP分析以及高并发低延时的SQL查询能力,使得HBase的应用可以从简单的在线查询应用扩展到复杂分析和在线应用结合的混合应用中,大大拓展了HBase的应用范围。
2.编程模型
TranswarpInceptor提供两种编程模型:一是基于SQL的编程模型,用于常规的数据分析、数据仓库类应用市场;二是基于数据挖掘编程模型,可以利用R语言或者SparkMLlib来做一些深度学习、数据挖掘等业务模型。
2.1SQL模型
TranswarpInceptor实现了自己的SQL解析执行引擎,可以兼容SQL99和HiveQL,自动识别语法,因此可以兼容现有的基于Hive开发的应用。由于TranswarpInceptor完整支持标准的SQL 99标准,传统数据库上运行的业务可以非常方便的迁移到Transwarp Inceptor系统上。此外Transwarp Inceptor支持PL/SQL扩展,传统数据仓库的基于PL/SQL存储过程的应用(如ETL工具)可以非常方便的在Inceptor上并发执行。另外Transwarp Inceptor支持部分SQL 2003标准,如窗口统计功能、安全审计功能等,并对多个行业开发了专门的函数库,因此可以满足多个行业的特性需求。
2.2数据挖掘计算模型
TranswarpInceptor实现了机器学习算法库与统计算法库,支持常用机器学习算法并行化与统计算法并行化,并利用Spark在迭代计算和内存计算上的优势,将并行的机器学习算法与统计算法运行在Spark上。例如:机器学习算法库有包括逻辑回归、朴素贝叶斯、支持向量机、聚类、线性回归、关联挖掘、推荐算法等,统计算法库包括均值、方差、中位数、直方图、箱线图等。TranswarpInceptor可以支持用R语言或者SparkAPI在平台上搭建多种分析型应用,例如用户行为分析、精准营销、对用户贴标签、进行分类。
3.SQL编译与优化
TranswarpInceptor研发了一套完整的SQL编译器,包括HiveQL解析器、SQL标准解析器和PL/SQL解析器,将不同的SQL语言解析成中间级表示语言,然后经过优化器转换成物理执行计划。SQL语言解析后经过逻辑优化器生成中间级表示语言,而中间表示语言再经过物理优化器生成最终的物理执行计划。从架构上分,逻辑优化器和物理优化器都包含基于规则的优化模块和基于成本的优化模块。
为了和Hadoop生态更好的兼容,Inceptor为一个SQL查询生成MapRece上的执行计划和Spark上的执行计划,并且可以通过一个SET命令在两种执行引擎之间切换。
3.1SQL编译与解析
TranswarpInceptor的SQL编译器会根据输入的SQL查询的类型来自动选择不同的解析器,如PL/SQL存储过程会自动进入PL/SQL解析器并生成一个SparkRDD的DAG从而在Spark平台上并行计算,标准SQL查询会进入SQL标准解析器生成Spark或MapRece执行计划。由于HiveQL和标准的SQL有所出入,为了兼容HiveQL,Transwarp Inceptor保留了HiveQL解析器,并可以对非标准SQL的Hive查询生成Spark或者Map Rece执行计划。
3.1.1SQL标准解析器
TranswarpInceptor构建了自主研发的SQL标准解析器,用于解析SQL99& SQL 2003查询并生成Spark和Map Rece的执行计划。词法和语法分析层基于Antlr语法来构建词法范式,通过Antlr来生成抽象语义树,并会通过一些上下文的语义来消除冲突并生成正确的抽象语义树。语义分析层解析上层生成的抽象语义树,根据上下文来生成逻辑执行计划并传递给优化器。首先Transwarp Inceptor会将SQL解析成TABLE SCAN、SELECT、FILTER、JOIN、UNION、ORDER BY、GROUP BY等主要的逻辑块,接着会根据一些Meta信息进一步细化各个逻辑块的执行计划。如TABLE SCAN会分成块读取、块过滤、行级别过滤、序列化等多个执行计划。
3.1.2PL/SQL解析器
PL/SQL是Oracle对SQL语言的模块化扩展,已经在很多行业中有大规模的应用,是数据仓库领域的重要编程语言。
为了让存储过程在Spark上有较好的性能,PL/SQL解析器会根据存储过程中的上下文关系来生成SQLDAG,然后对各SQL的执行计划生成的RDD进行二次编译,通过物理优化器将一些没有依赖关系的RDD进行合并从而生成一个最终的RDDDAG。因此,一个存储过程被解析成一个大的DAG,从而stage之间可以大量并发执行,避免了多次执行SQL的启动开销并保证了系统的并发性能。
解析并生成SQL级别的执行计划
3.2SQL优化器
TranswarpInceptor使用Spark作为默认计算引擎,并且开发了完善的SQL优化器,因此在大量的客户案例性能测试中,TranswarpInceptor的性能领先MapRece 10-100倍,并超越部分开源MPP数据库。SQL优化器对平台性能的提升居功至伟。
3.2.1基于规则的优化器(RuleBasedOptimizer)
目前为止,TranswarpInceptor共实现了一百多个优化规则,并且在持续的添加新的规则。按照功能划分,这些规则主要分布在如下几个模块:
文件读取时过滤
在文件读取时过滤数据能够最大化的减少参与计算的数据量从而最为有效的提高性能,因此TranswarpInceptor提供了多个规则用于生成表的过滤条件。对于一些SQL中的显示条件,TranswarpInceptor会尽量将过滤前推到读取表中;而对于一些隐式的过滤条件,如可以根据joinkey生成的过滤规则,Inceptor会根据语义保证正确性的前提下进行规则生成。
过滤条件前置
TranswarpInceptor能够从复杂的组合过滤条件中筛选出针对特定表的过滤规则,然后通过SQL语义来确定是否能将过滤条件前推到尽量早的时候执行。如果有子查询,过滤条件可以递归前推入最低层的子查询中,从而保证所有的冗余数据被删除。
超宽表的读取过滤
对一些列超多的表进行处理的时候,TranswarpInceptor首先会根据SQL语义来确定要读取的列,并在读取表的时候进行跨列读取减少IO和内存消耗。而如果表有过滤条件,Inceptor会做进一步优化,首先只读取过滤条件相关的列来确定该行记录是否需要被选择,如果不是就跳过当前行的所有列,因此能够最大程度上的减少数据读取。在一些商业实施中,这些优化规则能够带来5x-10x的性能提升。
Shuffle Stage的优化与消除
Spark的shuffle实现的效率非常低,需要把结果写磁盘,然后通过HTTP传输。TranswarpInceptor添加了一些shuffle消除的优化规则,对SQL的DAG中不必要或者是可以合并的shufflestage进行消除或者合并。对于必须要做Shuffle的计算任务,Inceptor通过DAGScheler来提高shuffle的效率:MapTask会直接将结果返回给DAGScheler,然后DAGScheler将结果直接交给Rece Task而不是等待所有Map Task结束,这样能够非常明显的提升shuffle阶段的性能。
Partition消除
TranswarpInceptor提供单一值Partition和RangePartition,并且支持对Partition建Bucket来做多次分区。当Partition过多的时候,系统的性能会因为内存消耗和调度开销而损失。因此,Inceptor提供了多个规则用于消除不必要的Partition,如果上下文中有隐式的对Partition的过滤条件,Inceptor也会生成对partition的过滤规则。
3.2.2基于成本的优化器(CostBasedOptimizer)
基于规则的优化器都是根据一些静态的信息来产生的,因此很多和动态数据相关的特性是不能通过基于规则的优化来解决,因此TranswarpInceptor提供了基于成本的优化器来做二次优化。相关的原始数据主要来自Meta-store中的表统计信息、RDD的信息、SQL上下文中的统计信息等。依赖于这些动态的数据,CBO会计算执行计划的物理成本并选择最有效的执行计划。一些非常有效的优化规则包括如下几点:
JOIN顺序调优
在实际的案例中,join是消耗计算量最多的业务,因此对join的优化至关重要。在多表JOIN模型中,TranswarpInceptor会根据统计信息来预估join的中间结果大小,并选择产生中间数据量最小的join顺序作为执行计划。
JOIN类型的选择
TranswarpInceptor支持Left-mostJoinTree 和 Bush Join Tree,并且会根据统计信息来选择生成哪种Join模型有最佳性能。此外,Transwarp Inceptor会根据原始表或者中间数据的大小来选择是否开启针对数据倾斜模型下的特殊优化等。此外,针对HBase表是否有索引的情况,Transwarp Inceptor会在普通Join和Look-up Join间做个均衡的选择。
并发度的控制
Spark通过线程级并发来提高性能,但是大量的并发可能会带来不必要的调度开销,因此不同的案例在不同并发度下会有最佳性能。TranswarpInceptor通过对RDD的一些属性进行推算来选择最佳并发控制,对很多的案例有着2x-3x的性能提升。
4.TranswarpHolodesk内存计算引擎
为了有效的降低SQL分析的延时,减少磁盘IO对系统性能的影响,星环科技研发了基于内存或者SSD的存储计算引擎TranswarpHolodesk,通过将表数据直接建在内存或者SSD上以实现SQL查询全内存计算。另外TranswarpHolodesk增加了数据索引功能,支持对多个数据列建索引,从而更大程度的降低了SQL查询延时。
4.1存储格式
TranswarpHolodesk基于列式存储做了大量的原创性改进带来更高的性能和更低的数据膨胀率。首先数据被序列化后存储到内存或SSD上以节省者资源占用。如图3所示,每个表的数据被存储成若干个Segment,每个Segment被划分成若干个Block,每个Block按照列方式存储于SSD或内存中。另外每个Block的头部都加上Min-MaxFilter和BloomFilter用于过滤无用的数据块,减少不必要的数据进入计算阶段。
TranswarpHolodesk根据查询条件的谓词属性对每个数据块的对应列构建数据索引,索引列采用自己研发的Trie结构进行组织存储,非索引列采用字典编码的方式进行组织存储。Trie不仅能对具有公共前缀的字符串进行压缩,而且可以对输入的字符串排序,从而可以利用二分查找快速查询所需数据的位置,从而快速响应查询需求。
HDFS2.6支持StorageTier让应用程序可以选择存储层为磁盘或者SSD,但是没有专用的存储格式设计是无法有效利用SSD的读写吞吐量和低延,因此现有的Text以及行列混合(ORC/Parquet)都不能有效的利用SSD的高性能。为此验证存储结构对性能的影响,我们将HDFS构建在SSD上并选用某基准测试来做了进一步的性能对比,结果如图4所示:采用文本格式,PCI-ESSD带来的性能提升仅1.5倍;采用专为内存和SSD设计的Holodesk列式存储,其性能相比较SSD上的HDFS提升高达6倍。
4.2性能优势
某运营商客户在12台x86服务器上搭建了TranswarpInceptor,将TranswarpHolodesk配置在PCIE-SSD上,并与普通磁盘表以及DB2来做性能对比测试。最终测试数据如图5所示:
在纯粹的count测试一项,Holodesk性能相对于磁盘表最高领先32倍;对于join测试一项,TranswarpHolodesk最高领先磁盘表多达12倍;在单表聚合测试中,Holodesk提升倍数达10~30倍。另外TranswarpHolodesk在和DB2的对比中也表现优秀,两个复杂SQL查询在DB2数据库中需要运行1小时以上,但是在使用TranswarpHolodesk均是分钟级和秒级就返回结果。
内存的价格大约是同样容量SSD的十倍左右,为了给企业提供更高性价比的计算方案,TranswarpHolodesk针对SSD进行了大量的优化,使得应用在SSD上运行具有与在内存上比较接近的性能,从而为客户提供了性价比更高的计算平台。
在对TPC-DS的IO密集型查询的测试中,无论上构建在PCI-ESSD还是内存上,Holodesk对比磁盘表有一个数量级上的性能提升;而SSD上的Holodesk性能只比内存差10%左右。
5.稳定的Spark执行引擎
企业目前应用开源Spark的主要困难在稳定性、可管理性和功能不够丰富上。开源Spark在稳定性上还有比较多的问题,在处理大数据量时可能无法运行结束或出现Outofmemory,性能时快时慢,有时比Map/Rece更慢,无法应用到复杂数据分析业务中。
TranswarpInceptor针对各种出错场景设计了多种解决方法,如通过基于成本的优化器选择最合适的执行计划、加强对数据结构内存使用效率的有效管理、对常见的内存出错问题通过磁盘进行数据备份等方式,极大提高了Spark功能和性能的稳定性,上述问题都已经解决并经过商业案例的考验。TranswarpInceptor能稳定的运行7*24小时,并能在TB级规模数据上高效进行各种稳定的统计分析。
6.SQL引擎效能验证
TPC-DS是TPC组织为DecisionSupportSystem设计的一个测试集,包含对大数据集的统计/报表生成/联机查询/数据挖掘等复杂应用,测试用的数据有各种不同的分布与倾斜,与真实场景非常接近。随着国内外各代表性的Hadoop发行版厂商以TPC-DS为标准测评产品,TPC-DS也就逐渐成为了业界公认的Hadoop系统测试准则。
6.1验证对比的平台和配置
我们搭建了两个集群分别用于TranswarpInceptor与ClouderaDataHub/Impala的测试。
6.2TranswarpInceptorVS Cloudera Impala
TranswarpInceptor由于有完善的SQL支持,能够运行全部所有的99个SQL查询。而由于Cloudera官方发布的TPC-DS测试集只包含19个SQL案例,因此我们只能运行这19个SQL,实验证明这部分查询在Impala上全部正常运行完成。
6.3TranswarpInceptorVS Map Rece
我们使用了同样的硬件和软件配置完成和开源的Hive执行效率相比,TranswarpInceptor能够带来10x-100x的性能提升。图8是TPC-DS的部分SQL查询在Inceptor和CDH5.1Hive的性能提升倍数,其中最大的提升倍数竟可达到123倍。
7.结语
随着在大数据领域国内外开始处于同一起跑线,我们相信像星环科技这样国内具有代表性的Hadoop发行版厂商将在中国的广阔市场空间中获得长足发展,并且由于中国市场激烈的竞争与磨练,逐步打磨出超越国外先进厂商的技术与实力。
刘汪根。2013年加入星环,作为早期员工参与了星环大数据平台的构建,现担任数据平台部研发经理,主要负责与管理星环大数据平台数据平台的研发工作,如SQL编译器,Spark执行引擎等工作,产品涵括TranswarpInceptor/TranswarpStream等软件。
【编者按】星环科技从2013年6月开始研发基于Spark的SQL执行引擎,在2013年底推出TranswarpInceptor1.0,并落地了国内首个7x24小时的商用项目。经过1年多的持续创新与改进,星环已经在国内落地了数十个Inceptor的商用项目。这是一篇星环Spark解决方案的技术解析,也是Spark用户可以效仿的优化之道。

② 了解什么叫做jit compiling,与传统的编译技术有何不同

java 应用程序的性能经常成为开发社区中的讨论热点。因为该语言的设计初衷是使用解释的方式支持应用程序的可移植性目标,早期
Java 运行时所提供的性能级别远低于 C 和
C++
之类的编译语言。尽管这些语言可以提供更高的性能,但是生成的代码只能在有限的几种系统上执行。在过去的十年中,Java
运行时供应商开发了一些复杂的动态编译器,通常称作即时(Just-in-time,JIT)编译器。程序运行时,JIT
编译器选择将最频繁执行的方法编译成本地代码。运行时才进行本地代码编译而不是在程序运行前进行编译(用 C 或
C++ 编写的程序正好属于后一情形),保证了可移植性的需求。有些 JIT 编译器甚至不使用解释程序就能编译所有的代码,但是这些编译器仍然通过在程序执行时进行一些操作来保持 Java 应用程序的可移植性。
由于动态编译技术的多项改进,在很多应用程序中,现代的 JIT 编译器可以产生与 C 或 C++
静态编译相当的应用程序性能。但是,仍然有很多软件开发人员认为 —— 基于经验或者传闻 ——
动态编译可能严重干扰程序操作,因为编译器必须与应用程序共享 CPU。一些开发人员强烈呼吁对 Java
代码进行静态编译,并且坚信那样可以解决性能问题。对于某些应用程序和执行环境而言,这种观点是正确的,静态编译可以极大地提高 Java
性能,或者说它是惟一的实用选择。但是,静态地编译 Java 应用程序在获得高性能的同时也带来了很多复杂性。一般的
Java 开发人员可能并没有充分地感受到 JIT 动态编译器的优点。

本文考察了 Java 语言静态编译和动态编译所涉及的一些问题,重点介绍了实时 (RT) 系统。简要描述了 Java
语言解释程序的操作原理并说明了现代 JIT 编译器执行本地代码编译的优缺点。介绍了 IBM 在 WebSphere Real Time 中发布的
AOT 编译技术和它的一些优缺点。然后比较了这两种编译策略并指出了几种比较适合使用 AOT
编译的应用程序领域和执行环境。要点在于这两种编译技术并不互斥:即使在使用这两种技术最为有效的各种应用程序中,它们也分别存在一些影响应用程序的优缺
点。

执行 Java 程序

Java 程序最初是通过 Java SDK 的 javac程序编译成本地的与平台无关的格式(类文件)。可将此格式看作 Java
平台,因为它定义了执行 Java 程序所需的所有信息。Java 程序执行引擎,也称作 Java 运行时环境(JRE),包含了为特定的本地平台实现
Java 平台的虚拟机。例如,基于 Linux 的 Intel x86 平台、Sun Solaris 平台和 AIX 操作系统上运行的 IBM
System p 平台,每个平台都拥有一个 JRE。这些 JRE 实现实现了所有的本地支持,从而可以正确执行为
Java 平台编写的程序。

事实上,操作数堆栈的大小有实际限制,但是编程人员极少编写超出该限制的方法。JVM 提供了安全性检查,对那些创建出此类方法的编程人员进行通知。

Java 平台程序表示的一个重要部分是字节码序列,它描述了 Java
类中每个方法所执行的操作。字节码使用一个理论上无限大的操作数堆栈来描述计算。这个基于堆栈的程序表示提供了平台无关性,因为它不依赖任何特定本地平台
的 CPU 中可用寄存器的数目。可在操作数堆栈上执行的操作的定义都独立于所有本地处理器的指令集。Java
虚拟机(JVM)规范定义了这些字节码的执行(参见 参考资料)。执行 Java 程序时,用于任何特定本地平台的任何 JRE 都必须遵守 JVM
规范中列出的规则。

因为基于堆栈的本地平台很少(Intel X87 浮点数协处理器是一个明显的例外),所以大多数本地平台不能直接执行 Java 字节码。为了解决这个问题,早期的 JRE 通过解释字节码来执行 Java 程序。即 JVM 在一个循环中重复操作:

◆获取待执行的下一个字节码;

◆解码;

◆从操作数堆栈获取所需的操作数;

◆按照 JVM 规范执行操作;

◆将结果写回堆栈。

这种方法的优点是其简单性:JRE 开发人员只需编写代码来处理每种字节码即可。并且因为用于描述操作的字节码少于 255 个,所以实现的成本比较低。当然,缺点是性能:这是一个早期造成很多人对 Java 平台不满的问题,尽管拥有很多其他优点。

解决与 C 或 C++ 之类的语言之间的性能差距意味着,使用不会牺牲可移植性的方式开发用于 Java 平台的本地代码编译。

编译 Java 代码

尽管传闻中 Java 编程的 “一次编写,随处运行”
的口号可能并非在所有情况下都严格成立,但是对于大量的应用程序来说情况确实如此。另一方面,本地编译本质上是特定于平台的。那么 Java
平台如何在不牺牲平台无关性的情况下实现本地编译的性能?答案就是使用 JIT 编译器进行动态编译,这种方法已经使用了十年(参见图 1):

图 1. JIT 编译器

使用 JIT 编译器时,Java
程序按每次编译一个方法的形式进行编译,因为它们在本地处理器指令中执行以获得更高的性能。此过程将生成方法的一个内部表示,该表示与字节码不同但是其级
别要高于目标处理器的本地指令。(IBM JIT
编译器使用一个表达式树序列表示方法的操作。)编译器执行一系列优化以提高质量和效率,最后执行一个代码生成步骤将优化后的内部表示转换成目标处理器的本
地指令。生成的代码依赖运行时环境来执行一些活动,比如确保类型转换的合法性或者对不能在代码中直接执行的某些类型的对象进行分配。JIT
编译器操作的编译线程与应用程序线程是分开的,因此应用程序不需要等待编译的执行。

图 1 中还描述了用于观察执行程序行为的分析框架,通过周期性地对线程取样找出频繁执行的方法。该框架还为专门进行分析的方法提供了工具,用来存储程序的此次执行中可能不会改变的动态值。

因为这个 JIT 编译过程在程序执行时发生,所以能够保持平台无关性:发布的仍然是中立的 Java 平台代码。C 和 C++ 之类的语言缺乏这种优点,因为它们在程序执行前进行本地编译;发布给(本地平台)执行环境的是本地代码。

挑战

尽管通过 JIT 编译保持了平台无关性,但是付出了一定代价。因为在程序执行时进行编译,所以编译代码的时间将计入程序的执行时间。任何编写过大型 C 或 C++ 程序的人都知道,编译过程往往较慢。

为了克服这个缺点,现代的 JIT
编译器使用了下面两种方法的任意一种(某些情况下同时使用了这两种方法)。第一种方法是:编译所有的代码,但是不执行任何耗时多的分析和转换,因此可以快
速生成代码。由于生成代码的速度很快,因此尽管可以明显观察到编译带来的开销,但是这很容易就被反复执行本地代码所带来的性能改善所掩盖。第二种方法是:
将编译资源只分配给少量的频繁执行的方法(通常称作热方法)。低编译开销更容易被反复执行热代码带来的性能优势掩盖。很多应用程序只执行少量的热方法,因
此这种方法有效地实现了编译性能成本的最小化。

动态编译器的一个主要的复杂性在于权衡了解编译代码的预期获益使方法的执行对整个程序的性能起多大作用。一个极端的例子是,程序执行后,您非常清楚哪些方
法对于这个特定的执行的性能贡献最大,但是编译这些方法毫无用处,因为程序已经完成。而在另一个极端,程序执行前无法得知哪些方法重要,但是每种方法的潜
在受益都最大化了。大多数动态编译器的操作介于这两个极端之间,方法是权衡了解方法预期获益的重要程度。

Java 语言需要动态加载类这一事实对 Java
编译器的设计有着重要的影响。如果待编译代码引用的其他类还没有加载怎么办?比如一个方法需要读取某个尚未加载的类的静态字段值。Java
语言要求第一次执行类引用时加载这个类并将其解析到当前的 JVM
中。直到第一次执行时才解析引用,这意味着没有地址可供从中加载该静态字段。编译器如何处理这种可能性?编译器生成一些代码,用于在没有加载类时加载并解
析类。类一旦被解析,就会以一种线程安全的方式修改原始代码位置以便直接访问静态字段的地址,因为此时已获知该地址。

IBM JIT
编译器中进行了大量的努力以便使用安全而有效率的代码补丁技术,因此在解析类之后,执行的本地代码只加载字段的值,就像编译时已经解析了字段一样。另外一
种方法是生成一些代码,用于在查明字段的位置以前一直检查是否已经解析字段,然后加载该值。对于那些由未解析变成已解析并被频繁访问的字段来说,这种简单
的过程可能带来严重的性能问题。

动态编译的优点

动态地编译 Java 程序有一些重要的优点,甚至能够比静态编译语言更好地生成代码,现代的 JIT 编译器常常向生成的代码中插入挂钩以收集有关程序行为的信息,以便如果要选择方法进行重编译,就可以更好地优化动态行为。

关于此方法的一个很好的例子是收集一个特定 array操作的长度。如果发现每次执行操作时该长度基本不变,则可以为最频繁使用的

array长度生成专门的代码,或者可以调用调整为该长度的代码序列。由于内存系统和指令集设计的特性,用于复制内存的最佳通用例程的执行速度通
常比用于复制特定长度的代码慢。例如,复制 8
个字节的对齐的数据可能需要一到两条指令直接复制,相比之下,使用可以处理任意字节数和任意对齐方式的一般复制循环可能需要 10 条指令来复制同样的 8

个字节。但是,即使此类专门的代码是为某个特定的长度生成的,生成的代码也必须正确地执行其他长度的复制。生成代码只是为了使常见长度的操作执行得更快,
因此平均下来,性能得到了改进。此类优化对大多数静态编译语言通常不实用,因为所有可能的执行中长度恒定的操作比一个特定程序执行中长度恒定的操作要少得
多。

此类优化的另一个重要的例子是基于类层次结构的优化。例如,一个虚方法调用需要查看接收方对象的类调用,以便找出哪个实际目标实现了接收方对象的虚方法。
研究表明:大多数虚调用只有一个目标对应于所有的接收方对象,而 JIT
编译器可以为直接调用生成比虚调用更有效率的代码。通过分析代码编译后类层次结构的状态,JIT
编译器可以为虚调用找到一个目标方法,并且生成直接调用目标方法的代码而不是执行较慢的虚调用。当然,如果类层次结构发生变化,并且出现另外的目标方法,
则 JIT
编译器可以更正最初生成的代码以便执行虚调用。在实践中,很少需要作出这些更正。另外,由于可能需要作出此类更正,因此静态地执行这种优化非常麻烦。

因为动态编译器通常只是集中编译少量的热方法,所以可以执行更主动的分析来生成更好的代码,使编译的回报更高。事实上,大部分现代的
JIT
编译器也支持重编译被认为是热方法的方法。可以使用静态编译器(不太强调编译时间)中常见的非常主动的优化来分析和转换这些频繁执行的方法,以便生成更好
的代码并获得更高的性能。

这些改进及其他一些类似的改进所产生的综合效果是:对于大量的 Java 应用程序来说,动态编译已经弥补了与 C 和 C++ 之类语言的静态本地编译性能之间的差距,在某些情况下,甚至超过了后者的性能。

缺点

但是,动态编译确实具有一些缺点,这些缺点使它在某些情况下算不上一个理想的解决方案。例如,因为识别频繁执行的方法以及编译这些方法需要时间,所以应用
程序通常要经历一个准备过程,在这个过程中性能无法达到其最高值。在这个准备过程中出现性能问题有几个原因。首先,大量的初始编译可能直接影响应用程序的
启动时间。不仅这些编译延迟了应用程序达到稳定状态的时间(想象 Web
服务器经
历一个初始阶段后才能够执行实际有用的工作),而且在准备阶段中频繁执行的方法可能对应用程序的稳定状态的性能所起的作用也不大。如果 JIT
编译会延迟启动又不能显着改善应用程序的长期性能,则执行这种编译就非常浪费。虽然所有的现代 JVM
都执行调优来减轻启动延迟,但是并非在所有情况下都能够完全解决这个问题。

其次,有些应用程序完全不能忍受动态编译带来的延迟。如 GUI 接口之类交互式应用程序就是这样的例子。在这种情况下,编译活动可能对用户使用造成不利影响,同时又不能显着地改善应用程序的性能。

最后,用于实时环境并具有严格的任务时限的应用程序可能无法忍受编译的不确定性性能影响或动态编译器本身的内存开销。

因此,虽然 JIT 编译技术已经能够提供与静态语言性能相当(甚至更好)的性能水平,但是动态编译并不适合于某些应用程序。在这些情况下,Java 代码的提前(Ahead-of-time,AOT)编译可能是合适的解决方案。

AOT Java 编译

大致说来,Java 语言本地编译应该是为传统语言(如 C++ 或
Fortran)而开发的编译技术的一个简单应用。不幸的是,Java 语言本身的动态特性带来了额外的复杂性,影响了 Java
程序静态编译代码的质量。但是基本思想仍然是相同的:在程序执行前生成 Java 方法的本地代码,以便在程序运行时直接使用本地代码。目的在于避免
JIT 编译器的运行时性能消耗或内存消耗,或者避免解释程序的早期性能开销。

挑战

动态类加载是动态 JIT 编译器面临的一个挑战,也是 AOT
编译的一个更重要的问题。只有在执行代码引用类的时候才加载该类。因为是在程序执行前进行 AOT
编译的,所以编译器无法预测加载了哪些类。就是说编译器无法获知任何静态字段的地址、任何对象的任何实例字段的偏移量或任何调用的实际目标,甚至对直接调
用(非虚调用)也是如此。在执行代码时,如果证明对任何这类信息的预测是错误的,这意味着代码是错误的并且还牺牲了 Java 的一致性。

因为代码可以在任何环境中执行,所以类文件可能与代码编译时不同。例如,一个 JVM
实例可能从磁盘的某个特定位置加载类,而后面一个实例可能从不同的位置甚至网络加载该类。设想一个正在进行 bug
修复的开发环境:类文件的内容可能随不同的应用程序的执行而变化。此外,Java 代码可能在程序执行前根本不存在:比如 Java
反射服务通常在运行时生成新类来支持程序的行为。

缺少关于静态、字段、类和方法的信息意味着严重限制了 Java 编译器中优化框架的大部分功能。内联可能是静态或动态编译器应用的最重要的优化,但是由于编译器无法获知调用的目标方法,因此无法再使用这种优化。

内联

内联是一种用于在运行时生成代码避免程序开始和结束时开销的技术,方法是将函数的调用代码插入到调用方的函数中。但是内联最大的益处可能是优化方可见的代码的范围扩大了,从而能够生成更高质量的代码。下面是一个内联前的代码示例:

int foo() { int x=2, y=3; return bar(x,y); }final int bar(int a, int b) { return a+b; }

如果编译器可以证明这个 bar就是 foo()中调用的那个方法,则 bar中的代码可以取代 foo()中对
bar()的调用。这时,bar()方法是 final类型,因此肯定是 foo()中调用的那个方法。甚至在一些虚调用例子中,动态 JIT
编译器通常能够推测性地内联目标方法的代码,并且在绝大多数情况下能够正确使用。编译器将生成以下代码:

int foo() { int x=2, y=3; return x+y; }

在这个例子中,简化前名为值传播的优化可以生成直接返回
5的代码。如果不使用内联,则不能执行这种优化,产生的性能就会低很多。如果没有解析
bar()方法(例如静态编译),则不能执行这种优化,而代码必须执行虚调用。运行时,实际调用的可能是另外一个执行两个数字相乘而不是相加的
bar方法。所以不能在 Java 程序的静态编译期间直接使用内联。

AOT
代码因此必须在没有解析每个静态、字段、类和方法引用的情况下生成。执行时,每个这些引用必须利用当前运行时环境的正确值进行更新。这个过程可能直接影响
第一次执行的性能,因为在第一次执行时将解析所有引用。当然,后续执行将从修补代码中获益,从而可以更直接地引用实例、静态字段或方法目标。

另外,为 Java 方法生成的本地代码通常需要使用仅在单个 JVM 实例中使用的值。例如,代码必须调用 JVM
运行时中的某些运行时例程来执行特定操作,如查找未解析的方法或分配内存。这些运行时例程的地址可能在每次将 JVM 加载到内存时变化。因此 AOT
编译代码需要绑定到 JVM 的当前执行环境中,然后才能执行。其他的例子有字符串的地址和常量池入口的内部位置。

在 WebSphere Real Time 中,AOT 本地代码编译通过 jxeinajar工具(参见图 2)来执行。该工具对 JAR 文件中所有类的所有方法应用本地代码编译,也可以选择性地对需要的方法应用本地代码编译。结果被存储到名为 Java eXEcutable (JXE) 的内部格式中,但是也可轻松地存储到任意的持久性容器中。

您可能认为对所有的代码进行静态编译是最好的方法,因为可以在运行时执行最大数量的本地代码。但是此处可以作出一些权衡。编译的方法越多,代码占用的内存
就越多。编译后的本地代码大概比字节码大 10 倍:本地代码本身的密度比字节码小,而且必须包含代码的附加元数据,以便将代码绑定到 JVM
中,并且在出现异常或请求堆栈跟踪时正确执行代码。构成普通 Java 应用程序的 JAR
文件通常包含许多很少执行的方法。编译这些方法会消耗内存却没有什么预期收益。相关的内存消耗包括以下过程:将代码存储到磁盘上、从磁盘取出代码并装入
JVM,以及将代码绑定到 JVM。除非多次执行代码,否则这些代价不能由本地代码相对解释的性能优势来弥补。

图 2. jxeinajar

跟大小问题相违背的一个事实是:在编译过的方法和解释过的方法之间进行的调用(即编译过的方法调用解释过的方法,或者相反)可能比这两类方法各自内部之间
进行的调用所需的开销大。动态编译器通过最终编译所有由 JIT
编译代码频繁调用的那些解释过的方法来减少这项开销,但是如果不使用动态编译器,则这项开销就不可避免。因此如果是选择性地编译方法,则必须谨慎操作以使
从已编译方法到未编译方法的转换最小化。为了在所有可能的执行中都避免这个问题而选择正确的方法会非常困难。
优点
虽然 AOT 编译代码具有上述的缺点和挑战,但是提前编译 Java 程序可以提高性能,尤其是在不能将动态编译器作为有效解决方案的环境中。

可以通过谨慎地使用 AOT 编译代码加快应用程序启动,因为虽然这种代码通常比 JIT
编译代码慢,但是却比解释代码快很多倍。此外,因为加载和绑定 AOT
编译代码的时间通常比检测和动态编译一个重要方法的时间少,所以能够在程序执行的早期达到那样的性能。类似地,交互式应用程序可以很快地从本地代码中获
益,无需使用引起较差响应能力的动态编译。

RT 应用程序也能从 AOT 编译代码中获得重要的收益:更具确定性的性能超过了解释的性能。WebSphere Real Time
使用的动态 JIT 编译器针对在 RT 系统中的使用进行了专门的调整。使编译线程以低于 RT
任务的优先级操作,并且作出了调整以避免生成带有严重的不确定性性能影响的代码。但是,在一些 RT 环境中,出现 JIT
编译器是不可接受的。此类环境通常需要最严格的时限管理控制。在这些例子中,AOT
编译代码可以提供比解释过的代码更好的原始性能,又不会影响现有的确定性。消除 JIT
编译线程甚至消除了启动更高优先级 RT 任务时发生的线程抢占所带来的性能影响。

优缺点统计

动态(JIT)编译器支持平台中立性,并通过利用应用程序执行的动态行为和关于加载的类及其层次结构的信息来生成高质量的代码。但是
JIT
编译器具有一个有限的编译时预算,而且会影响程序的运行时性能。另一方面,静态(AOT)编译器则牺牲了平台无关性和代码质量,因为它们不能利用程序的动
态行为,也不具有关于加载的类或类层次结构的信息。AOT 编译拥有有效无限制的编译时预算,因为 AOT
编译时间不会影响运行时性能,但是在实践中开发人员不会长期等待静态编译步骤的完成。

表 1 总结了本文讨论的 Java 语言动态和静态编译器的一些特性:

表 1. 比较编译技术

两种技术都需要谨慎选择编译的方法以实现最高的性能。对动态编译器而言,编译器自身作出决策,而对于静态编译器,由开发人员作出选择。让
JIT 编译器选择编译的方法是不是优点很难说,取决于编译器在给定情形中推断能力的好坏。在大多数情况下,我们认为这是一种优点。

因为它们可以最好地优化运行中的程序,所以 JIT 编译器在提供稳定状态性能方面更胜一筹,而这一点在大量的生产 Java
系统中最为重要。静态编译可以产生最佳的交互式性能,因为没有运行时编译行为来影响用户预期的响应时间。通过调整动态编译器可以在某种程度上解决启动和确
定性性能问题,但是静态编译在需要时可提供最快的启动速度和最高级别的确定性。表 2 在四种不同的执行环境中对这两种编译技术进行了比较:

表 2. 使用这些技术的最佳环境

图 3 展示了启动性能和稳定状态性能的总体趋势:

图 3. AOT 和 JIT 的性能对比

使用 JIT 编译器的初始阶段性能很低,因为要首先解释方法。随着编译方法的增多及 JIT
执行编译所需时间的缩短,性能曲线逐渐升高最后达到性能峰值。另一方面,AOT 编译代码启动时的性能比解释的性能高很多,但是无法达到 JIT
编译器所能达到的最高性能。将静态代码绑定到 JVM 实例中会产生一些开销,因此开始时的性能比稳定状态的性能值低,但是能够比使用 JIT
编译器更快地达到稳定状态的性能水平。

没有一种本地代码编译技术能够适合所有的 Java
执行环境。某种技术所擅长的通常正是其他技术的弱项。出于这个原因,需要同时使用这两种编译技术以满足 Java
应用程序开发人员的要求。事实上,可以结合使用静态和动态编译以便提供最大可能的性能提升 —— 但是必须具备平台无关性,它是 Java
语言的主要卖点,因此不成问题。

结束语

本文探讨了 Java 语言本地代码编译的问题,主要介绍了 JIT 编译器形式的动态编译和静态 AOT 编译,比较了二者的优缺点。

虽然动态编译器在过去的十年里实现了极大的成熟,使大量的各种 Java 应用程序可以赶上或超过静态编译语言(如 C++ 或
Fortran)所能够达到的性能。但是动态编译在某些类型的应用程序和执行环境中仍然不太合适。虽然 AOT
编译号称动态编译缺点的万能解决方案,但是由于 Java 语言本身的动态特性,它也面临着提供本地编译全部潜能的挑战。

这两种技术都不能解决 Java 执行环境中本地代码编译的所有需求,但是反过来又可以在最有效的地方作为工具使用。这两种技术可以相互补充。能够恰当地使用这两种编译模型的运行时系统可以使很大范围内的应用程序开发环境中的开发人员和用户受益。

③ atlas 鏄浠涔堢殑缂╁啓锛

C/ATLAS鍏ㄧОCommon / Abbreviated Test Language for All Systems(鍏ㄧ郴缁熷叕鍏/绠鏄庢祴璇曡瑷)鏄涓涓骞挎硾鐢ㄤ簬鍐涗簨鍜岃埅绌烘祴璇旷殑镙囧嗳鍖栬瑷.鐢盗EEE璐熻矗瀵硅ヨ瑷镙囧嗳杩涜岀$悊缁存姢,璁稿氩浗瀹堕兘鍙傚姞浜呜繖涓璇瑷镄勫紑鍙.链鏂囦粙缁岖殑姝f槸鎴戝浗寮鍙戠殑ATLAS缂栬疟鍣ㄤ腑镄勮涔夊垎鏋愰儴鍒.
璇涔夊垎鏋愭槸缂栬疟涓镄勯吨镣,鍦ㄨ涔夊垎鏋愪腑涓崭粎瑕佽繘琛岀▼搴忕殑涓娄笅鏂囱涔変竴镊存х殑妫镆,杩樿佷负鐩镙囦唬镰佺敓鎴愭彁渚涜冻澶熺殑淇℃伅.链鏂囦粙缁崭简ATLAS璇涔夊垎鏋愮殑瀹炵幇鏂规硶,骞跺笰TLAS绯荤粺镄勫疄鐜版妧链,杩愯岀幆澧幂殑瀹炵幇鏂规硶杩涜屼简绠鍗旷殑浠嬬粛.
瀵逛簬ATLAS璇涔変腑瑕佹眰镄勭壒娈婇梾棰,鎴戜滑閲囩敤浜嗛溃钖戝硅薄鎶链锷犱互瀹炵幇,骞跺彇寰椾简寰埚ソ镄勭粨鏋.鍏蜂綋镄勫疄鐜伴噰鐢ㄩ润镐佽涔夊垎鏋愬拰锷ㄦ佽涔夊垎鏋愮浉缁揿悎镄勬柟娉.链鏂囧笰TLAS绯荤粺涓镄勮惧囩$悊绯荤粺,杩愯岀幆澧幂郴缁熺瓑涔熻繘琛屼简绠鍗旷殑浠嬬粛,涓篈TLAS绯荤粺镄勮繘涓姝ュ紑鍙戝犲畾浜嗗熀纭.
鐩 褰
绗涓绔 绯荤粺绠浠
1.1 ATLAS 绯荤粺绠浠
C/ATLAS鏄鍏ㄧ郴缁熷叕鍏/绠鏄庢祴璇曡瑷(Common / Abbreviated Test Language for All Systems)镄勭缉鍐,瀹冩槸涓绉嶅姛鑳藉崄鍒嗗己澶х殑鍏ㄧ郴缁熸爣鍑嗘祴璇曡瑷,鍦ㄥ啗浜,鑸绌轰簨涓氢腑鍏锋湁骞挎硾镄勫簲鐢.
20涓栫邯60骞翠唬,ARINC鍏鍙镐负浜嗗硅埅绌哄櫒涓婄殑鐢靛瓙璁惧囩郴缁熻繘琛屾祴璇,涓诲姙寮鍙戜简涓涓娴嬭瘯璇瑷ATLAS,褰撴椂ATLAS镄勫惈涔夋槸鎸嘇bbreviated Test Language for Avionics Systems .闅忓悗,缇庡浗闄嗗啗,娴峰啗,鑸绌洪儴阒熶互鍙婂寳澶цタ娲嫔叕绾︾粍缁囦篃锷犲叆鍒拌繖涓璇瑷镄勫紑鍙.
1976骞,C/ATLAS镄勬带鍒舵潈鐢盇RINC绉讳氦缁橧EEE,姝ゆ椂ATLAS镄勫惈涔夋洿涓哄箍娉:Abbreviated Test Language for All Systems .钖屾椂ARINC鍙戝竷浜咺EEE镙煎纺镄𪞝RINC416-13A镙囧嗳.1988骞,IEEE鍙戝竷浜咥TLAS716-1988/9镙囧嗳,钖屽勾ARINC涔熷彂甯冧简镙囧嗳ARINC626-1988/9,涔嫔悗IEEE鍜孉RINC姣忎笁,锲涘勾灏辨洿鏂颁竴娆″悇镊镄勬爣鍑.2000骞,IEEE鍙戝竷浜咰/ATLAS镄勬渶鏂扮増链珹TLAS2000镙囧嗳,鎴戜滑瀹炵幇镄勭郴缁熼噰鐢ㄧ殑灏辨槸IEEE镄𪞝TLAS2000镙囧嗳.
C/ATLAS鍏锋湁濡备笅镄勭壒镣:
涓,瀹冩槸涓涓镙囧嗳镄勬祴璇曡瑷.涓轰简阒叉㈣瑷镄勬棩鐩婂签澶у拰涓嶅埄浜庣淮鎶,璇ヨ瑷鐢盗EEE璐熻矗鍙戝竷鐩稿簲镄勬爣鍑,浠ヨ揪鍒拌瑷镄勮勮寖鍜岀粺涓.鍙备笌璇ユ爣鍑嗙殑涓昏佺敤鎴锋湁缇庡浗锲介槻閮,寰峰浗锲介槻閮,娉曞浗锲介槻閮,鑻卞浗锲介槻閮,鐟炲吀锲介槻閮ㄥ拰鑸绌哄伐涓氱殑鑸绌烘棤绾跨数鍏鍙哥瓑.
浜,C/ATLAS鍏锋湁鍜屾祴璇曡惧囨棤鍏崇殑鐗规,鍙搴旂敤浜庢墍链夌殑娴嬭瘯绯荤粺.鐢ˋTLAS璇瑷缂栧啓镄勭▼搴忓彲浠ユ祴璇曞悇绉崭华鍣ㄨ惧,娴嬭瘯镄勪唬镰佷腑涓嶅寘𨰾浠讳綍娴嬭瘯镓閲囩敤镄勭‖浠朵俊鎭.涔熷氨鏄璇,鍙瑕佹祴璇曚娇鐢ㄧ殑镊锷ㄦ祴璇曡惧(ATE)鏀鎸丄TLAS,渚垮彲浠ヤ笉缁忚繃淇鏀瑰湴浣跨敤鍦ㄥ彟澶栦竴涓娴嬭瘯绯荤粺涓缂栧啓镄𪞝TLAS绋嫔簭.
涓,ATLAS镄勫姛鑳藉崄鍒嗗己澶,鎻愪緵浜嗙湡姝g殑镊锷ㄦ祴璇.鍦ㄤ互寰镄勬祴璇曚腑,娴嬭瘯浜哄憳涓崭粎瑕佽冭槛娴嬭瘯镄勭畻娉曞拰娴佺▼,杩樿佽姳寰埚氱簿锷涚敤浜庨夋嫨娴嬭瘯浣跨敤镄勮惧囩敋镊宠捐℃祴璇曟墍闇镄勭‖浠剁瓑,杩涜屼笉钖岀殑娴嬭瘯闇瑕佷笉钖岀殑娴嬭瘯璁惧囧拰鐩稿簲镄勬祴璇曟祦绋.鍦ˋTLAS涓鍒欎笉闇瑕佹祴璇曚汉锻樿冭槛娴嬭瘯纭浠,钥岀敱ATLAS绯荤粺镊锷ㄥ勭悊,杩欐牱娴嬭瘯浜哄憳灏辫兘澶熸洿锷犱笓蹇冨湴杩涜屾祴璇旷畻娉曞拰娴嬭瘯娴佺▼璁捐.ATLAS绯荤粺镄𪞝TE(镊锷ㄦ祴璇曡祫婧)涓鎻愪緵浜嗗ぇ閲忕殑娴嬭瘯璁惧,涓涓狝TE鑳借繘琛屽緢澶氭祴璇,杩欐牱涓崭粎绠鍖栦简娴嬭瘯绯荤粺镄勮勬ā,涔熷ぇ澶ф彁楂树简娴嬭瘯镄勬晥鐜囧拰姘村钩.
1.1.1 杩涜孉TLAS 娴嬭瘯镄勭‖浠剁幆澧
ATLAS璇瑷鍙浠ュ簲鐢ㄤ簬钖勭岖数瀛愮被鍜岄潪鐢电被浠鍣ㄨ惧囩殑娴嬭瘯,闅忕潃娴嬭瘯鎶链鍜屾祴璇曡惧囩殑涓嶆柇鍙戝𪾢,ATLAS璇瑷涔熷湪涓嶆柇镄勮繘琛屼慨鏀.鍦ㄩ伒寰狪EEE镙囧嗳镄勫熀纭涓,涓轰简鏂逛究鐢ㄦ埛镄勪娇鐢,ATLAS璇瑷镊韬鎻愪緵浜嗕竴绉岖殑镓╁𪾢链哄埗,浠ュ畬鎴愮敱浜庡綋鍓嶆爣鍑嗙殑闄愬埗钥屼笉鑳借繘琛岀殑娴嬭瘯.
ATLAS 璇瑷涓涓嶆彁渚涙祴璇旷‖浠朵俊鎭.鐢ㄦ埛浣跨敤杩囩▼涓,ATLAS绯荤粺镙规嵁绋嫔簭涓镄勮惧囩壒寰佷俊鎭,镊锷ㄥ湴杩涜岃惧囧垎閰嶅苟璋幂敤鐩稿簲镄勭‖浠舵搷浣沧潵瀹屾垚瀵筓UT(琚娴嬭瘯鍗曞厓)镄勬祴璇.鍙浠ヨ碅TLAS绯荤粺鏄涓涓瀵规祴璇曡蒋浠跺拰纭浠惰繘琛岀$悊镄勮櫄𨰾熸満,瀹冧笉浠呰礋璐e笰TLAS婧愮▼搴忕紪璇,鐢熸垚链哄櫒镰;杩樿佸规祴璇曡祫婧愯惧囱繘琛岀$悊,璁惧囩$悊鍖呮嫭:娣诲姞鍜屽垹闄よ惧,绠$悊琚娴嬭瘯鍗曞厓(UUT)鍒拌嚜锷ㄦ祴璇旷郴缁(ATE)璁惧囩殑寮鍏宠繛鎺ラ氲矾;姝ゅ,ATLAS绯荤粺杩樿佸湪娴嬭瘯镄勬墽琛岃繃绋嬩腑,澶勭悊娴嬭瘯涓浜х敓镄勪簨浠,骞剁洃鎺ф祴璇曡祫婧愮殑宸ヤ綔𨱍呭喌.
涓嫔浘鏄疉TLAS娴嬭瘯镄勭‖浠剁幆澧.
,ATLAS娴嬭瘯绯荤粺纭浠剁粨鏋勫浘
ATLAS娴嬭瘯绯荤粺纭浠朵富瑕佹湁浠ヤ笅鍑犱釜閮ㄥ垎缁勬垚:
ATE(auto test equipment):镊锷ㄦ祴璇曡惧,浣挎暣涓娴嬭瘯绯荤粺镄勬牳蹇,閲囩敤VXI鎴朓EEE488 镐荤嚎灏呜惧囱繛鎺ュ埌涓绘満涓.ATE链烘煖涓镄勮惧囦富瑕佸寘𨰾:1)娴嬭瘯浣跨敤镄勮祫婧,濡傚悇绉嶅彲鎺х洿娴佺数婧,鍙鎺т俊鍙峰彂鐢熷櫒,鏁板瓧涓囩敤琛,绀烘尝鍣ㄧ瓑;2)寮鍏宠惧,鐢ㄤ簬杩炴帴ATE澶栭儴镄勯樀鍒楁帴鍙e拰ATE鍐呴儴镄勮惧.3)ATE阒靛垪鎺ュ彛,鏄疉TE镄勮緭鍑烘帴鍙,澶栨帴娴嬭瘯浣跨敤镄勯傞厤鍣.
UUT(unit under test):琚娴嬭瘯鍗曞厓,鍗虫祴璇旷殑瀵硅薄,鍦ㄦ祴璇曡繃绋嬩腑鍜孉TE澶栭儴镄勯傞厤鍣ㄧ浉杩炴帴.
阃傞厤鍣:鐢ㄤ簬杩炴帴ATE鍜孶UT.鍦ㄦ祴璇曡繃绋嬩腑,ATE璐熻矗鎻愪緵缁橴UT (琚娴嬭瘯鍗曞厓)鐢垫簮,杈揿叆镄勬縺锷变俊鍙,骞朵粠UUT (琚娴嬭瘯鍗曞厓)涓璇诲嚭娴嬭瘯镣圭殑鍐呭.阃傞厤鍣ㄧ殑浣灭敤灏辨槸杩涜屼粠ATE(镊锷ㄦ祴璇曡惧)鍒癠UT(琚娴嬭瘯鍗曞厓)寤虹珛鐩稿簲镄勮繛鎺,骞舵牴鎹甎UT 𨱍呭喌杩涜岀数姘旇浆鎹,鐢典俊鍙峰埌闱炵数淇″彿镄勮浆鎹㈢瓑.
VXI 镐荤嚎绛:鐢ㄤ簬杩炴帴涓绘満鍜孉TE(镊锷ㄦ祴璇曡祫婧)涓镄勬祴璇曡惧,鍙鎺у紑鍏崇瓑,杩涜孉TE鎺у埗鍜屾暟鎹阃氢俊.
涓绘満:娴嬭瘯涓绘带璁$畻链,鍏朵笂闱㈣繍琛孉TLAS绯荤粺.
1.1.2.ATLAS 绯荤粺缁撴瀯
ATLAS绯荤粺璐熻矗缂栬疟镓ц孉TLAS缂栧啓镄勬祴璇旷▼搴,鎻愪緵璋冭瘯鐜澧,娴嬭瘯浠跨湡鐜澧,绠$悊ATE涓镄勫悇绉嶈惧囧拰寮鍏.ATLAS绯荤粺鐢盇TLAS缂栬疟鍣,ATLAS杩愯岀幆澧,ATLAS鐜澧幂$悊绋嫔簭,璁惧囧簱,镓╁𪾢鍗忚,镐荤嚎鎻忚堪鏂囦欢,璁惧囨弿杩版枃浠,寮鍏虫弿杩版枃浠跺拰阃傞厤鍣ㄦ弿杩版枃浠剁粍鎴.
绯荤粺镄勭粨鏋勫备笅锲炬墍绀:
ATLAS绯荤粺娴嬭瘯娴佺▼锲
ATLAS 鐜澧幂$悊绋嫔簭灏嗘祴璇曚娇鐢ㄧ殑璁惧囨弿杩版枃浠,寮鍏虫弿杩版枃浠,镐荤嚎鎻忚堪鏂囦欢鍜岄傞厤鍣ㄦ弿杩版枃浠惰浆鎹涓哄唴閮ㄧ殑璁惧囦俊鎭,寮鍏充俊鎭,镐荤嚎淇℃伅鍜岄傞厤鍣ㄥ紩鑴氢俊鎭.
ATLAS缂栬疟鍣ㄥ皢娴嬭瘯绋嫔簭缂栬疟鎴愬彲镓ц岀殑鐩镙囦唬镰,骞朵氦缁橝TLAS杩愯岀郴缁熸墽琛.鍦ㄧ紪璇戠殑杩囩▼涓,ATLAS缂栬疟鍣ㄦ牴鎹绯荤粺涓镄勮惧囦俊鎭,寮鍏充俊鎭,镐荤嚎鍜岄傞厤鍣ㄥ紩鑴氢俊鎭,杩涜屾祴璇曡惧囩殑鍒嗛厤,鐢熸垚鐩稿簲娴嬭瘯璁惧囩殑镎崭綔浠g爜,骞跺湪娴嬭瘯缁撴潫钖庡洖鏀惰惧.
ATLAS杩愯岀郴缁熻礋璐f墽琛岀洰镙囦唬镰,瀹屾垚链缁堢殑娴嬭瘯.鍦ㄨ繍琛岀郴缁熶腑瑕佺洃鎺ц惧囩殑镓ц屾儏鍐,澶勭悊𨱒ヨ嚜娴嬭瘯璁惧囩殑淇″彿鍜屼腑鏂,绠$悊娴嬭瘯镓ц岀殑杩涚▼,骞剁粰绋嫔簭锻樻彁渚涚浉搴旂殑璋冭瘯鐜澧.
鍦ㄦ墽琛屼腑,ATLAS镄勮繍琛岀郴缁熻皟鐢ㄨ惧喽LL搴扑腑镄勮惧囧嚱鏁版潵镓ц屾祴璇.璁惧囩$悊绯荤粺璐熻矗娣诲姞娴嬭瘯璁惧,淇鏀瑰紑鍏抽氲矾,淇鏀规祴璇曡惧囦俊鎭,鍒犻櫎娴嬭瘯璁惧囩瓑绛.娣诲姞鍜屼慨鏀逛竴涓璁惧囧垯鐩稿簲镄勪慨鏀硅惧喽LL搴.
ATLAS缂栬疟鍣ㄦ牴鎹婧愮▼搴忎腑璁惧囩殑鐗瑰緛淇℃伅,缁揿悎绯荤粺鍐呴儴镄勮惧囦俊鎭,寮曡剼淇℃伅鍜屽紑鍏充俊鎭,𨱒ユ煡镓捐惧.濡傛灉镓惧埌婊¤冻𨱒′欢镄勮惧,鍒椤垎閰嶈ヨ惧囧苟璋幂敤杩欎釜璁惧囩殑镎崭綔.濡傛灉镟存敼绯荤粺镄勮惧,姣斿傛坊锷犳柊璁惧囨垨淇鏀瑰綋鍓嶈惧囩殑镆愪簺淇℃伅,杩欐椂瑕佷慨鏀圭郴缁熷唴閮ㄧ殑璁惧囦俊鎭,浠ヤ究鍦ˋTLAS缂栬疟镞惰兘澶熸垒鍒版弧瓒虫浔浠剁殑璁惧.
1.2 链鏂囧畬鎴愮殑宸ヤ綔
链鏂囦粙缁岖殑宸ヤ綔鏄鎴戜滑镄勯”鐩钬斺擜TLAS绯荤粺镄勪竴閮ㄥ垎,涓昏佹槸ATLAS璇瑷镄勮涔夊垎鏋愰儴鍒,缁椤嚭浜咥TLAS褰㈠纺鍖栬涔,ATLAS缂栬疟鐜澧,杩愯岀幆澧,ATLAS镄勫姩镐佽涔夊垎鏋愭妧链鍜岄润镐佽涔夊垎鏋愭妧链.链鏂囧畬鎴愮殑宸ヤ綔链:
瀹炵幇浜咥TLAS璇瑷镄勮涔夊垎鏋
鍒╃敤闱㈠悜瀵硅薄镄勬妧链痆5][6]瑙e喅浜咥TLAS瑕佹眰镄勮涔夋墿灞曞拰璁惧囨棤鍏虫
阒愯堪浜咥TLAS绯荤粺镄勭粍鎴愬拰钖勯儴鍒嗙殑锷熻兘
瀹炵幇浜咥TLAS镄勮涔夊垎鏋愬櫒[7],缁椤嚭浜咥TLAS闱欐佽涔夋镆ュ拰锷ㄦ佽涔夋镆ョ殑鍐呭,骞跺埄鐢ㄥ睘镐ф枃娉曞姞浠ユ弿杩
绗浜岀珷 ATLAS璇瑷
2.1 ATLAS 2000
ATLAS鏄涓涓鍗佸垎链夎叮镄勮瑷,涓庝竴鑸镄勮繃绋嫔纺璇瑷涓嶅悓,ATLAS镟存帴杩戜簬镊铹惰瑷.鍦ㄨ繖涓璇瑷涓姣忎竴涓璇鍙ョ敱锷ㄨ瘝,钖嶈瘝鍜屽畠浠镄勪慨楗颁俊鎭缁勬垚,涓涓狝TLAS璇鍙ヤ腑镊冲皯鍖呭惈涓涓锷ㄨ瘝鍜屼竴涓钖嶈瘝[2].
ATLAS2000璇鍙ョ粨鏋勫备笅锲炬墍绀:
锲哄畾锘 鍒嗛殧绗
,
锲哄畾锘熶腑镄勬爣蹇楀烟,鐢ㄦ潵璇存槑杩欐浔璇鍙ョ殑钖涔,濡傛灉蹇界暐镙囧织璇存槑鏄涓𨱒℃櫘阃氱殑璇鍙,鏄娉ㄩ喷璇鍙ュ垯镙囧织涓"C" 鎴"B",濡傛灉鏄"E"琛ㄧず鍙浠ヤ粠镙囧织镄勮繖𨱒¤鍙ュ紑濮嬫墽琛屾祴璇,钥屼笌鍓嶉溃镄勬祴璇曟棤鍏.
VERB锷ㄨ瘝,鍖呮嫭ATLAS涓镄勫姩璇嶅拰锷ㄨ瘝淇楗拌瘝.锷ㄨ瘝链:APPLY,DEFINE,DECLARE,REQUIRE,DISCONNECT,REMOVE,DO绛.锷ㄨ瘝镄勪慨楗拌瘝鐢ㄦ潵杈呭姪锷ㄨ瘝濡:"DO ,SIMULTANEOUS" 璇鍙ヤ腑镄凷IMULANEOUS,淇″彿璇鍙ヤ腑镄"THEN RESET"绛.
鍒嗛殧绗,鍦ˋTLAS涓涓嶅悓镄勮娉曟垚鍒嗙敱鍒嗛殧绗","闅斿紑.
姣忎竴𨱒¢兘链変竴涓缁堟㈢"$".
姣忎釜璇鍙ョ殑璇鍙ュ墿浣欓儴鍒嗘牴鎹𨱍呭喌钥屽畾.
ATLAS2000缁撴瀯:
ATLAS2000 鏄涓涓链夊氩眰缁撴瀯镄勮瑷[4],涓涓狝TLAS绋嫔簭鐢辨牳瀛愬师璇,璇鍙,妯″瀷,TTF鍜屾ā鍧楃粍鎴.ATLAS镙稿瓙閮ㄥ垎鍜孉TLAS铡熻鏋勬垚浜呜繖涓璇瑷镄勫熀纭,鐢ㄦ埛阃氲繃棰勫畾涔夊拰杩欎簺锘烘湰璇绱犳潵寤虹珛娴嬭瘯椤圭洰镄勯渶姹.妯″瀷缁撴瀯浣跨敤鎴烽氲繃瀵瑰簳灞傞儴浠剁殑镎崭綔缁勫悎,鎶借薄鍑哄叿链夋洿楂桦眰娆$殑缁撴瀯骞跺规洿澶嶆潅镄勬祴璇曞姛鑳藉姞浠ユ弿杩.TTF(Test Technology Frameworks)娴嬭瘯鎶链妗嗘灦,ATLAS2000娴嬭瘯鎶链妗嗘灦鍖呮嫭骞跺畾涔変竴浜涚敱ATLAS2000锘虹缁勬垚镄勭壒娈婄殑娴嬭瘯鐜澧.妯″潡鐢ㄦ潵灏佽呴偅浜涘彲閲嶅崭娇鐢ㄧ殑娴嬭瘯浠g爜.鍏蜂綋缁撴瀯濡备笅锲炬墍绀:
ATLAS 2000 缁撴瀯锲
娉ㄩ喷:
ATLAS镙稿瓙閮ㄥ垎(NUCLEUS)瀹氢箟浜咥TLAS璇瑷鍏稿瀷镄勬ц兘鍜屽姛鑳.ATLAS镙稿瓙鐢卞舰寮忚娉,淇濈暀瀛楀拰瑙勫垯涓変釜閮ㄥ垎缁勬垚.
ATLAS铡熻(PRIMITIVES)鏄鎻忚堪鍜岃存槑ATLAS淇″彿,锷ㄤ綔,灞炴у拰镐ц兘蹇呴渶镄勫厓绱.杩欎簺锘烘湰鍏幂礌涓嶈兘鍐嶅垎,鍏朵腑鍖呮嫭钖嶈瘝,钖嶈瘝淇楗拌瘝,锷ㄨ瘝,锷ㄨ瘝淇楗拌瘝,镎崭綔绗︿互鍙婂畠浠镄勫姛鑳藉畾涔.
ATLAS妯″瀷(MODELS)鏄涓绯诲垪鍑芥暟鍜岃繃绋嬬殑琛ㄧず,鍦ˋTLAS涓,妯″瀷鐢ㄦ潵鎻忚堪娴嬭瘯璁惧囧拰琚娴嬭瘯鍗曞厓(UUT)镄勭壒寰.ATLAS妯″瀷鏄鏂囨硶鍏幂礌镄勬弿杩板熀纭,ATLAS鍏抽敭瀛楁牴鎹瓵TLAS2000妯″瀷𨱒ュ畾涔,镓链夌殑鍏抽敭瀛楀繀椤绘ā鍨嫔寲.涓镞︿竴涓妯″瀷琚瀹氢箟骞朵笖鎴愪负娴嬭瘯鎶链妗嗘灦(TTF)镄勪竴閮ㄥ垎,灏卞彲浠ュ湪ATLAS镄勮鍙ヤ腑浣滀负涓涓鍏抽敭瀛楁潵浣跨敤.
ATLAS镄勬ā鍧(MODULE)鏄鍖呭惈鍦ˋTLAS绋嫔簭涓镄勪竴涓瀹炰綋,鍙浠ヨ村畠鏄涓涓鍖呭惈ATLAS杩囩▼鍜岄潪ATLAS杩囩▼镄勫瑰櫒.鍦ˋTLAS涓鐢"INCLUDE"璇鍙ユ潵浣跨敤妯″潡.鍦ㄦā鍧楀唴阃氲繃澹版槑杩囩▼镄勫睘镐ф槸鍏ㄥ眬镄勮缮鏄灞閮ㄧ殑,𨱒ュ喅瀹氲繃绋嬬殑浣灭敤锘,鍏ㄥ眬镄勮繃绋嫔彲浠ュ湪妯″潡澶栦娇鐢.鍦ㄦā鍧楀唴閮ㄥ彲浣跨敤链妯″潡瀹氢箟镄勬墍链夎繃绋,阃氲繃瀵瑰叾瀹幂殑妯″潡杩涜屽紩鐢ㄥ0鏄,涔熷彲浣跨敤澶栭儴杩囩▼.
2.2 ATLAS 璇涔夊垎鏋愮壒镣
ATLAS璇瑷鏄鐢ㄤ簬娴嬭瘯镄勬爣鍑呜瑷.灏界″湪ATLAS璇瑷涓娌℃湁鍏充簬娴嬭瘯璁惧囩‖浠剁殑鍏蜂綋淇℃伅,濡傝惧囩殑鐗╃悊鍦板潃,璁惧囬┍锷ㄧ▼搴忓拰璁惧囩殑镎崭綔鍑芥暟绛,浣嗘槸ATLAS鎻愪緵浜嗘弿杩拌惧囩壒寰佺殑铡熻鍜屾ā鍨媅1][3],鍏朵腑鍖呮嫭:钖嶈瘝,锷ㄨ瘝,淇楗拌瘝,杩炴帴鍜屼俊鍙蜂缭鐣椤瓧绛.ATLAS缂栬疟鍣ㄦf槸镙规嵁鍦ˋTLAS绋嫔簭涓镄勭敱杩欎簺铡熻鍜屾ā鍨嬬粍鎴愮殑淇℃伅,𨱒ヨ嚜锷ㄥ湴瀹屾垚璁惧囨煡镓,璁惧囧垎閰,铡婚厤鍜屾搷浣.
鍜屽父瑙佺殑绋嫔簭璇瑷鐩告瘆,ATLAS链澶х殑鐗圭偣灏辨槸鍖呮嫭浜嗕竴浜涗笌娴嬭瘯璁惧囨垨琚娴嫔崟鍏幂浉鍏崇殑淇℃伅鍜岃鍙[1],钥屽规祴璇曡惧囱繘琛屾搷浣滀篃灏辨槸ATLAS璇涔夌殑閲嶈侀儴鍒.鐜板湪鎴戜滑𨱒ュ规瘆涓涓闱濧TLAS璇瑷鍜孉TLAS璇瑷鏄濡备綍缂栧啓娴嬭瘯绋嫔簭镄.
鎴戜滑浠嶤璇瑷镄勬祴璇旷▼搴忓拰ATLAS璇瑷缂栧啓镄勫悓镙峰姛鑳界殑绋嫔簭杩涜屼竴涓嫔规瘆.
渚:灏嗕竴涓鐢靛帇鏄28v镄勭洿娴佺数婧愯繛鎺ュ埌琚娴嬭瘯璁惧(UUT)涓.
瀹炵幇:
鐢–璇瑷缂栧啓娴嬭瘯绋嫔簭镄勫叿浣撴搷浣沧ラゆ槸:棣栧厛灏呜佷娇鐢ㄧ殑鐢垫簮杩炴帴鍒版祴璇旷郴缁熶笂,灏嗙数婧愬埌UUT镄勫紑鍏崇疆涓鸿繛鎺,铹跺悗璁剧疆鐢垫簮鐢靛帇涓28V,鎺ヤ笅𨱒ユ镆ョ数婧愮殑杈揿嚭鐢靛帇鏄钖︽槸28V,宸ヤ綔鐢垫祦鏄钖﹀皬浜1A,濡傛灉婊¤冻𨱒′欢鍒椤厑璁歌ョ数婧愬伐浣.
鍦ˋTLAS涓,阃氲繃涓𨱒$亩鍗旷殑璇鍙ュ氨鍙浠ュ畬鎴愪简杩欎簺镎崭綔,鍦ˋTLAS绋嫔簭涓涓嶉渶瑕佹寚鍑鸿佷娇鐢ㄥ摢涓涓鐢垫簮,鎴戜滑鍙浠ョ湅鍑篈TLAS鍜孋璇瑷镄勪笉钖屼箣澶.鍦–镄勭▼搴忎腑鐢辨祴璇曞憳鎸囧畾瑕佷娇鐢ㄧ殑鐢垫簮骞惰繛鎺ヨ繖涓鐢垫簮镄勪娇鐢ㄧ殑寮鍏宠繖镙锋潵瀹屾垚娴嬭瘯,鍦ˋTLAS杩欎簺宸ヤ綔涓鍒欑敱缂栬疟鍣ㄨ嚜锷ㄥ畬鎴.
C璇瑷鍜孉TLAS璇瑷缂栧啓镄勪唬镰佹瘆杈冨备笅:

鎽樿嚜锛歴oftlab.jlu.e.cn/temp/thesis/2004liulei.doc

④ 编程怎么做怎么编代码java 我不会

1.如何学习程序设计?
JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于JAVA,对C++等其他程序设计语言也一样管用。有编程高手认为,JAVA也好C也好没什么分别,拿来就用。为什么他们能达到如此境界?我想是因为编程语言之间有共通之处,领会了编程的精髓,自然能够做到一通百通。如何学习程序设计理所当然也有许多共通的地方。1 培养兴趣 2 慎选程序设计语言 3 要脚踏实地,快餐式的学习不可取 4 多实践,快实践5 多参考程序代码
6 加强英文阅读能力 7 万不得已才请教别人8 多读好书
9 使用合适的工具 学习JAVAJAVA学习路线
1 基础语法及JAVA原理
基础语法和JAVA原理是地基,地基不牢靠,犹如沙地上建摩天大厦,是相当危险的。学习JAVA也是如此,必须要有扎实的基础,你才能在J2EE、J2ME领域游刃有余。参加SCJP(SUN公司认证的JAVA程序员)考试不失为一个好方法,原因之一是为了对得起你交的1200大洋考试费,你会更努力学习,原因之二是SCJP考试能够让你把基础打得很牢靠,它要求你跟JDK一样熟悉JAVA基础知识;但是你千万不要认为考过了SCJP就有多了不起,就能够获得软件公司的青睐,就能够获取高薪,这样的想法也是很危险的。获得"真正"的SCJP只能证明你的基础还过得去,但离实际开发还有很长的一段路要走。
2 OO思想的领悟
掌握了基础语法和JAVA程序运行原理后,我们就可以用JAVA语言实现面向对象的思想了。面向对象,是一种方法学;是独立于语言之外的编程思想;是CBD基于组件开发的基础;属于强势技术之一。当以后因工作需要转到别的面向对象语言的时候,你会感到特别的熟悉亲切,学起来像喝凉水这么简单。
使用面向对象的思想进行开发的基本过程是:
●调查收集需求。
●建立用例模型。
●从用例模型中识别分析类及类与类之间的静态动态关系,从而建立分析模型。
●细化分析模型到设计模型。
●用具体的技术去实现。
●测试、部署、总结。
3 基本API的学习
进行软件开发的时候,并不是什么功能都需要我们去实现,也就是经典名言所说的"不需要重新发明轮子"。我们可以利用现成的类、组件、框架来搭建我们的应用,如SUN公司编写好了众多类实现一些底层功能,以及我们下载过来的JAR文件中包含的类,我们可以调用类中的方法来完成某些功能或继承它。那么这些类中究竟提供了哪些方法给我们使用?方法的参数个数及类型是?类的构造器需不需要参数?总不可能SUN公司的工程师打国际长途甚至飘洋过海来告诉你他编写的类该如何使用吧。他们只能提供文档给我们查看,JAVADOC文档(参考文献4.4)就是这样的文档,它可以说是程序员与程序员交流的文档。
基本API指的是实现了一些底层功能的类,通用性较强的API,如字符串处理/输入输出等等。我们又把它成为类库。熟悉API的方法一是多查JAVADOC文档(参考文献4.4),二是使用JBuilder/Eclipse等IDE的代码提示功能4 特定API的学习
JAVA介入的领域很广泛,不同的领域有不同的API,没有人熟悉所有的API,对一般人而言只是熟悉工作中要用到的API。如果你做界面开发,那么你需要学习Swing/AWT/SWT等API;如果你进行网络游戏开发,你需要深入了解网络API/多媒体API/2D3D等;如果你做WEB开发,就需要熟悉Servlet等API啦。总之,需要根据工作的需要或你的兴趣发展方向去选择学习特定的API。
5 开发工具的用法
在学习基础语法与基本的面向对象概念时,从锻炼语言熟练程度的角度考虑,我们推荐使用的工具是Editplus/JCreator+JDK,这时候不要急于上手JBuilder/Eclipse等集成开发环境,以免过于关注IDE的强大功能而分散对JAVA技术本身的注意力。过了这一阶段你就可以开始熟悉IDE了。
程序员日常工作包括很多活动,编辑、编译及构建、调试、单元测试、版本控制、维持模型与代码同步、文档的更新等等,几乎每一项活动都有专门的工具,如果独立使用这些工具的话,你将会很痛苦,你需要在堆满工具的任务栏上不断的切换,效率很低下,也很容易出错。在JBuilder、Eclipse等IDE中已经自动集成编辑器、编译器、调试器、单元测试工具JUnit、自动构建工具ANT、版本控制工具CVS、DOC文档生成与更新等等,甚至可以把UML建模工具也集成进去,又提供了丰富的向导帮助生成框架代码,让我们的开发变得更轻松。应该说IDE发展的趋势就是集成软件开发中要用到的几乎所有工具。
从开发效率的角度考虑,使用IDE是必经之路,也是从一个学生到一个职业程序员转变的里程碑。
JAVA开发使用的IDE主要有Eclipse、JBuilder、JDeveloper、NetBeans等几种;而Eclipse、JBuilder占有的市场份额是最大的。JBuilder在近几年来一直是JAVA集成开发环境中的霸主,它是由备受程序员尊敬的Borland公司开发,在硝烟弥漫的JAVAIDE大战中,以其快速的版本更新击败IBM的VisualAgeforJAVA等而成就一番伟业。IBM在VisualAgeforJAVA上已经无利可图之下,干脆将之贡献给开源社区,成为Eclipse的前身,真所谓"柳暗花明又一村"。浴火重生的Eclipse以其开放式的插件扩展机制、免费开源获得广大程序员(包括几乎所有的骨灰级程序员)的青睐,极具发展潜力。
6 学习软件工程
对小型项目而言,你可能认为软件工程没太大的必要。随着项目的复杂性越来越高,软件工程的必要性才会体现出来。参见"软件开发学习路线"小节。
7 学习要点
确立的学习路线之后,我们还需要总结一下JAVA的学习要点,这些要点在前文多多少少提到过,只是笔者觉得这些地方特别要注意才对它们进行汇总,不要嫌我婆婆妈妈啊。
8 勤查API文档
当程序员编写好某些类,觉得很有成就感,想把它贡献给各位苦难的同行。这时候你要使用"javadoc"工具(包含在JDK中)生成标准的JAVADOC文档,供同行使用。J2SE/J2EE/J2ME的DOC文档是程序员与程序员交流的工具,几乎人手一份,除了菜鸟之外。J2SEDOC文档官方下载地址: http://java.sun.com/j2se/1.5.0/download.jsp,你可以到google搜索CHM版本下载。也可以在线查看: http://java.sun.com/j2se/1.5.0/docs/api/index.html。
对待DOC文档要像毛主席语录,早上起床念一遍,吃饭睡觉前念一遍。
当需要某项功能的时候,你应该先查相应的DOC文档看看有没有现成的实现,有的话就不必劳神费心了直接用就可以了,找不到的时候才考虑自己实现。使用步骤一般如下:
●找特定的包,包一般根据功能组织。
●找需要使用类,类命名规范的话我们由类的名字可猜出一二。
●选择构造器,大多数使用类的方式是创建对象。
●选择你需要的方法。
9 查书/google->写代码测试->查看源代码->请教别人
当我们遇到问题的时候该如何解决?
这时候不要急着问别人,太简单的问题,没经过思考的问题,别人会因此而瞧不起你。可以先找找书,到google中搜一下看看,绝大部分问题基本就解决了。而像"某些类/方法如何使用的问题",DOC文档就是答案。对某些知识点有疑惑是,写代码测试一下,会给你留下深刻的印象。而有的问题,你可能需要直接看API的源代码验证你的想法。万不得已才去请教别人。
10学习开源软件的设计思想
JAVA领域有许多源代码开放的工具、组件、框架,JUnit、ANT、Tomcat、Struts、Spring、Jive论坛、PetStore宠物店等等多如牛毛。这些可是前辈给我们留下的瑰宝呀。入宝山而空手归,你心甘吗?对这些工具、框架进行分析,领会其中的设计思想,有朝一日说不定你也能写一个XXX框架什么的,风光一把。分析开源软件其实是你提高技术、提高实战能力的便捷方法。
11规范的重要性
没有规矩,不成方圆。这里的规范有两层含义。第一层含义是技术规范,多到 http://www.jcp.org下载JSRXXX规范,多读规范,这是最权威准确最新的教材。第二层含义是编程规范,如果你使用了大量的独特算法,富有个性的变量及方法的命名方式;同时,没给程序作注释,以显示你的编程功底是多么的深厚。这样的代码别人看起来像天书,要理解谈何容易,更不用说维护了,必然会被无情地扫入垃圾堆。JAVA编码规范到此查看或下载 http://java.sun.com/docs/codeconv/,中文的也有,啊,还要问我在哪,请参考3.2.2节。
12 不局限于JAVA
很不幸,很幸运,要学习的东西还有很多。不幸的是因为要学的东西太多且多变,没时间陪老婆家人或女朋友,导致身心疲惫,严重者甚至导致抑郁症。幸运的是别人要抢你饭碗绝非易事,他们或她们需要付出很多才能达成心愿。
JAVA不要孤立地去学习,需要综合学习数据结构、OOP、软件工程、UML、网络编程、数据库技术等知识,用横向纵向的比较联想的方式去学习会更有效。如学习JAVA集合的时候找数据结构的书看看;学JDBC的时候复习数据库技术;采取的依然是"需要的时候再学"的原则。

⑤ 谁能简单阐述下java编译执行的过程

Java虚拟机(JVM)是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行。本文首先简要介绍从Java文件的编译到最终执行的过程,随后对JVM规格描述作一说明。

一.Java源文件的编译、下载、解释和执行
Java应用程序的开发周期包括编译、下载、解释和执行几个部分。Java编译程序将Java源程序翻译为JVM可执行代码?字节码。这一编译过程同C/C++的编译有些不同。当C编译器编译生成一个对象的代码时,该代码是为在某一特定硬件平台运行而产生的。因此,在编译过程中,编译程序通过查表将所有对符号的引用转换为特定的内存偏移量,以保证程序运行。Java编译器却不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由解释器在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。这样就有效的保证了Java的可移植性和安全性。

运行JVM字节码的工作是由解释器来完成的。解释执行过程分三部进行:代码的装入、代码的校验和代码的执行。装入代码的工作由"类装载器"(class loader)完成。类装载器负责装入运行一个程序需要的所有代码,这也包括程序代码中的类所继承的类和被其调用的类。当类装载器装入一个类时,该类被放在自己的名字空间中。除了通过符号引用自己名字空间以外的类,类之间没有其他办法可以影响其他类。在本台计算机上的所有类都在同一地址空间内,而所有从外部引进的类,都有一个自己独立的名字空间。这使得本地类通过共享相同的名字空间获得较高的运行效率,同时又保证它们与从外部引进的类不会相互影响。当装入了运行程序需要的所有类后,解释器便可确定整个可执行程序的内存布局。解释器为符号引用同特定的地址空间建立对应关系及查询表。通过在这一阶段确定代码的内存布局,Java很好地解决了由超类改变而使子类崩溃的问题,同时也防止了代码对地址的非法访问。

随后,被装入的代码由字节码校验器进行检查。校验器可发现操作数栈溢出,非法数据类型转化等多种错误。通过校验后,代码便开始执行了。

Java字节码的执行有两种方式:
1.即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。
2.解释执行方式:解释器通过每次解释并执行一小段代码来完成Java字节码程 序的所有操作。
通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作

具有较高的效率。对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。

二.JVM规格描述
JVM的设计目标是提供一个基于抽象规格描述的计算机模型,为解释程序开发人员提很好的灵活性,同时也确保Java代码可在符合该规范的任何系统上运行。JVM对其实现的某些方面给出了具体的定义,特别是对Java可执行代码,即字节码(Bytecode)的格式给出了明确的规格。这一规格包括操作码和操作数的语法和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量缓冲池在JVM的存储映象。这些定义为JVM解释器开发人员提供了所需的信息和开发环境。Java的设计者希望给开发人员以随心所欲使用Java的自由。

JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是:
JVM指令系统
JVM寄存器
JVM栈结构
JVM碎片回收堆
JVM存储区

2.1JVM指令系统

JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由 操作码和操作数两部分组成。操作码为8位二进制数,操作数进紧随在操作码的后面,其长度根据需要而不同。操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的"与",ret用于流程控制,表示从对某一方法的调用中返回。当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了"big endian"的编码方式来处理这种情况,即高位bits存放在低字节中。这同 Motorola及其他的RISC CPU采用的编码方式是一致的,而与Intel采用的"little endian "的编码方式即低位bits存放在低位字节的方法不同。

Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多先程系统的指令。Java的8位操作码的长度使得JVM最多有256种指令,目前已使用了160多种操作码。

2.2JVM指令系统

所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了4个最为常用的寄存器。它们是:
pc程序计数器
optop操作数栈顶指针
frame当前执行环境指针
vars指向当前执行环境中第一个局部变量的指针
所有寄存器均为32位。pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。

2.3JVM栈结构

作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息:
局部变量
执行环境
操作数栈

局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。
执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是一个执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。
操作数栈用于存储运算所需操作数及运算的结果。

2.4JVM碎片回收堆

Java类的实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕,便将其回收到堆中。
在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。

2.5JVM存储区

JVM有两类存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。

JVM是为Java字节码定义的一种独立于具体平台的规格描述,是Java平台独立性的基础。目前的JVM还存在一些限制和不足,有待于进一步的完善,但无论如何,JVM的思想是成功的。

对比分析:如果把Java原程序想象成我们的C++原程序,Java原程序编译后生成的字节码就相当于C++原程序编译后的80x86的机器码(二进制程序文件),JVM虚拟机相当于80x86计算机系统,Java解释器相当于80x86CPU。在80x86CPU上运行的是机器码,在Java解释器上运行的是Java字节码。

Java解释器相当于运行Java字节码的“CPU”,但该“CPU”不是通过硬件实现的,而是用软件实现的。Java解释器实际上就是特定的平台下的一个应用程序。只要实现了特定平台下的解释器程序,Java字节码就能通过解释器程序在该平台下运行,这是Java跨平台的根本。当前,并不是在所有的平台下都有相应Java解释器程序,这也是Java并不能在所有的平台下都能运行的原因,它只能在已实现了Java解释器程序的平台下运行。

⑥ 有哪些体系结构模式

一、体系结构定义:

体系结构是一个计算机术语,由G. Amdahl于1964年首次提出体系结构概念,为以后计算机系统的设计与开发奠定了良好的基础。体系结构包括数据流系统、调用-返回系统、独立部件、虚拟机、以数据为中心的系统(库)、特殊领域风格、特殊结构风格、不同风格合成建立的异构结构、最初始最基本的主程序/子程序九大内容。

二、体系结构由来:

在传统的程序设计领域中,人们使用流程图来表达系统的基本功能和实现的具体逻辑,但是,流程图实际上仅仅是源程序的图形化表示,无法给系统的分析和开发者提供更多的信息,所以没有在实际的系统开发过程中得到广泛的应用。随着软件系统的规模和复杂性的增加,对软件系统的整体结构(数据和控制的逻辑)进行分析和描述成为大型系统开发的一个不可缺少的重要部分,显然,使用流程图是无法达到这个目标的,我们必须使用新的方法和概念来对系统的整体结构进行把握。

三、体系结构的分类:

1.数据流系统,包括顺序批处理、管道和过滤器;

2. 调用-返回系统,包括主程序和子程序、面向对象系统、层次结构;

3. 独立部件,包括通信进程、事件隐式调用;

4.虚拟机,包括解释器、规则基系统;

5. 以数据为中心的系统(库),包括数据库、超文本系统、黑板系统;

6. 特殊领域风格;例如过程控制、模拟器;

7. 特殊结构的风格,例如分布式处理、状态转移系统;

8. 不同风格合成建立的异构结构;

9. 最初始、最基本的主程序/子程序。

四、结构范式:

1.管道和过滤器

每个组件具有输入和输出的集合,从流中读出数据作为输入,产生输出数据的流。整个系统可以看成多个过滤器复合形成的数据处理组件。

过滤器A

过滤器B

过滤器C

管道

特点:

过滤器之间是相互独立的(不能共享状态),其中一个过滤器的操作和行为不能影响另外过滤器的操作和行为,流的传送没有副作用。

过滤器对所输入流的来源和输出流的去向不关心,不需要知道流的来源和流的去向,来源和去向对于过滤器的数据处理没有任何影响。

过滤和流的传送可以是并发的,可以同时有多个流的传送存在于系统之中。

实例:

一个最着名的实例是unix的shell编程,多个对数据进行处理的程序(组件)通过管道联结起来,产生总和的效果;还有传统的编译器,源代码经过词法分析、语法分析、中间代码生成、目标代码生成等步骤生成输出的目标代码。

优点:

整个系统的功能是多个过滤器作用的总和,这样可以简化系统的分析和设计,可以经过需求的分析之后将整个系统作为一个过滤器处理,然后再逐步的细化成为多个相互连接的过滤器。

支持组件的重用,同一个过滤器可以多次出现在系统的不同位置。

易于维护和增强,过滤器可以被替换,可以增加新的过滤器到系统中而不改变原有的过滤器,不改变原来系统的基本功能。

本质上的并发性支持,这种体系结构由于本质上是与各个独立的过滤器的状态无关的,与并行的流的通过次序也是无关的,所以并发是一个基本的体系结构自然具有的特性。

缺点:

由于过滤器之间本质上是独立的,所以设计者必须独立考虑每一个过滤器的输入、处理和输出的过程,对于过滤器逻辑上的共同点和相互关系无法在设计中加以体现。

由于这种体系的批处理特性,所以不适合开发和用户交互的应用程序。

系统的多个处理流之间的共同特性无法提取、多个过滤器之间的共同特性也无法提取,所以增加了设计的复杂性。

2.面向对象的体系

在这种体系中,数据和数据上的操作被封装成抽象数据类型或者对象。系统由大量的对象组成,在物理上,对象之间通过函数或者过程调用相互作用;在逻辑上,对象之间通过集成、复合等方式实现设计的复用。

对象D

对象B

对象A

对象E

对象C

对象调用

对象调用

对象调用

类A

类B

类C

类G

对象A

对象E

类F

复合

继承

物理结构逻辑结构

特点:

面向对象系统分析和设计的资料已经太多,这里就不再详细说明了。

优点:

由于封装,实现了灵活性和扩充性,隐藏了实现的细节,提高代码的质量;

使用继承和多态、提高了软件的可重用性。

缺点:

最主要的缺点是,由于对象之间的交互是通过明确的对象函数调用进行的,所以当一个对象需要实现一个特定功能的时候,必须知道哪一个对象提供这种服务,这就降低了系统的灵活性。管道和过滤器模型不需要明确指明数据的来源和去向。

事件驱动的体系

对象E

对象E

对象E

事件分发的总线

事件的创建

事件接收者的注册的创建

对象E

这是面向对象和数据抽象体系的一种变形,系统同样是由大量的对象组成的,但是对象之间的交互不是通过明确指明对象的函数或者过程调用进行的,相反,系统提供事件的创建和发布的机制,对象产生事件,一个或者多个对象通过向系统注册关注这个事件并由此触发出相应的行为或者产生新的事件。

实例:

一个最着名的例子是GUI的模型,鼠标、键盘或者其他输入设备产生各种事件,窗口、程序或者其他对象有这些事件所触发,产生新的事件、进行数据处理或者其他操作。

优点:

用于函数和过程的调用调用不需要指明特定的对象,所以系统具有非常好的灵活性和扩展性,新的组件只需要向系统的事件处理部分注册就可以立刻加入系统中,同样,老的组件也可以方便的从系统中删除。对于动态性要求特别高的系统,特别是如果需要在运行时对系统进行扩充,应该采用该结构。

缺点:

由于函数调用是通过事件发送进行的,所以,发出事件的对象不能确认是否有对象处理了这个事件、是否是期望的对象处理了这个事件、是否获得期望的结果,同样也无法控制事件发生的次序,系统的逻辑和时序的正确性必须通过复杂的时序逻辑和前后条件的断言加以保证。

3.分层次的体系

将系统功能和组件分成不同的功能层次,一般而言,只有最上层的组件和功能可以被系统外的使用者访问,只有相邻的层次之间才能够有函数调用。

下面是一个基本的商务处理系统的层次结构:

用户界面层

事务逻辑层

核心层

实例:

显然,ISO的OSI(开放系统互连)参考模型是最着名的层次模型的例子,通过将开放系统的功能和组件划分成7个层次,定义清晰的(很多时候是过于复杂的)层次之间的接口,实现复杂的互操作性。

优点:

系统的开发和设计可以逐步的分层次的进行,从底层的简单的功能逐步建立高层的复杂和抽象的功能。

灵活性和扩展性,由于相邻层次之间通过清晰的接口交互,所以特定的层次可以被替换和增强,甚至可以增加新的层次。

缺点:

不是所有的系统都可以分解成为清楚的层次

划分清晰、逻辑上一致的层次是非常困难的(OSI的失败和TCP/IP的成功说明了这一点)

严格的层次调用结构会降低系统的性能。

4.知识库体系

使用一个中心数据结构表示系统的当前状态,一组相互独立的组件在中心数据库上进行操作。如果组件负责对中心数据进行选择、处理,这种体系就是传统的数据库模型;如果中心数据结构自主的引发一系列的行为,则这种体系可以看成一个黑板模型。

中心数据库(知识库)

客户组件A

客户组件B

客户组件C

实例:

大量的传统数据库应用程序实际上就是这一体系的具体实例。在很多研究系统中,使用的基于知识库的黑板模型,实际上也是这种体系

优点:

以数据为中心的体系结构,可以自然的表示大量的数据和事务处理的逻辑,适合表达以数据为重新的应用程序。

缺点:

只有很少一部分简单的数据库存储应用可以完全采用这种体系结构表示,在大量实际的商业应用中,完成师傅处理和其他逻辑的应用程序必须采用其他的体系结构表达

5.解释器体系

用户

如果应用程序的逻辑非常复杂,例如,AutoCAD的各种绘图指令,而且,用户可能以非常复杂的方式使用这个系统,一个较好的体系就是提供面向领域的一组指令(语言),系统解释这种语言,产生相应的行为,用户使用这种指令(语言)完成复杂的操作。

使用虚拟机语言描述的业务逻辑

虚拟机解释器

完成实际操作任务的基本指令

实际的问题领域

实例:

大量的开发工具、二次开发工具体现了这一思想:微软在其产品中大量使用的Visual Basic for Application,以及在AutoDesk产品中大量使用的AutoLisp语言,实际上就是给用户提供了一种面向领域的语言,然后核心解释执行这一语言的指令和指令序列。从而扩充产品的功能,方便用户按照自己的需要定制系统。

优点:

非常好的扩展性,用户可以实现对软件系统的二次开发

缺点:

软件开发复杂,特别是这种指令集的设计非常困难。

是否可以采用一种成熟的语言作为二次开发的基础(例如,基于Java)



⑦ 编译器笔记6-词法分析-有穷自动机

有穷自动机(Finite Automata,FA)由两位神经物理学MeCuloch和Pitts于1948年首先提出,是对 一类处理系统建立的数学模型。这类系统具有一系列离散的输入输出信息和有穷数目的内部状态(状态:概括了对过去输入信息处理的状况)。

系统只需要根据当前所处的状态 和 当前面临的输入信息就可以决定系统的后继行为。每当系统处理了当前的输入后,系统的内部 状态也将发生改变。

电梯控制装置

输入:顾客的乘梯需求(所要到达的层号)
状态:电梯所处的层数+

电梯控制装置并不需要记住先前全部的服务要
求,只需要知道电梯当前所处的状态以及还没
有满足的所有服务请求。

输入带 (input tape) :用来存放输入符号串。

读头 (head) :从左向右逐个读取输入符号,不能修改(只读)、不能往返移动。

有穷控制器 ( finite control ) :具有有穷个状态数,根据当前的
状态和当前输入符号控制转入 下一状态。

确定的FA (Deterministic finite automata, DFA)
非确定的FA (Nondeterministic finite automata, NFA)

M = (S,Σ,δ,s0,F)

例:一个DFA

M = (S,Σ ,δ,s0,F)

M = (S,Σ,δ,s0,F)

例:一个NFA
M = (S,Σ,δ,s0,F)

对任何非确定的有穷自动机N,存在定义同一语言的确定的有穷自动机D。对任何确定的有穷自动机D,存在定义同一语言的非确定的有穷自动机N。

DFA和NFA可以识别相同的语言

M = (S,Σ,δ,s0,F)

从正则表达式到NFA相对直接到DFA比较简单,再从NFA转到DFA。

例 r=(a|b)* abb 对应的NFA

与NFA等价的DFA的每个状态都是NFA状态的一个子集

move(T,a)获得的是一个状态集合U,ε-closure(move(T,a))即为ε-closure(U)对应上表的第二个操作。所以理解上述函数关键是理解closure(T),该操作其实就是求得一个状态集合只通过ε转换得到的另外一个集合。

热点内容
剑击脚本 发布:2024-11-07 13:39:12 浏览:204
python强转 发布:2024-11-07 13:32:35 浏览:1000
方块方舟如何架设服务器 发布:2024-11-07 13:08:37 浏览:366
什么5v5安卓和苹果都可以联机 发布:2024-11-07 13:03:03 浏览:772
数字证书连接不上服务器地址 发布:2024-11-07 13:00:50 浏览:915
mysql导出数据库结构 发布:2024-11-07 13:00:49 浏览:467
360如何清除缓存 发布:2024-11-07 12:59:38 浏览:497
ftp服务器c语言 发布:2024-11-07 12:45:15 浏览:97
delphijava 发布:2024-11-07 12:40:35 浏览:465
sqlserver查询数据 发布:2024-11-07 12:40:28 浏览:7