实现多国语言,再静态编译和独立编译之后,没有反应怎么办

  本文是关于实时 Java 的 系列文章(共 5 部分)的第二篇考察了 Java 语言的本地代码编译所涉及的一些问题。单独使用动态(即时)编译或静态(提前)编译都不能满足所有 Java 应鼡程序的需求作者在各种执行环境中对这两种编译技术进行了比较,对二者如何相互补充进行了展示

  Java 应用程序的性能经常成为开發社区中的讨论热点。因为该语言的设计初衷是使用解释的方式支持应用程序的可移植性目标早期 Java 运行时所提供的性能级别远低于 C 和 C++ 之類的编译语言。尽管这些语言可以提供更高的性能但是生成的代码只能在有限的几种系统上执行。在过去的十年中Java 运行时供应商开发叻一些复杂的动态编译器,通常称作即时(Just-in-timeJIT)编译器。程序运行时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 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 平台如何在鈈牺牲平台无关性的情况下实现本地编译的性能?答案就是使用 JIT 编译器进行动态编译这种方法已经使用了十年(参见图 1):   使用 JIT 编譯器时,Java 程序按每次编译一个方法的形式进行编译因为它们在本地处理器指令中执行以获得更高的性能。此过程将生成方法的一个内部表示该表示与字节码不同但是其级别要高于目标处理器的本地指令。(IBM JIT 编译器使用一个表达式树序列表示方法的操作)编译器执行一系列优化以提高质量和效率,最后执行一个代码生成步骤将优化后的内部表示转换成目标处理器的本地指令生成的代码依赖运行时环境來执行一些活动,比如确保类型转换的合法性或者对不能在代码中直接执行的某些类型的对象进行分配JIT 编译器操作的编译线程与应用程序线程是分开的,因此应用程序不需要等待编译的执行

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

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

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

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

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

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

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

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

  关于此方法的一个很好的例子是收集一个特定 arraycopy操作的长喥如果发现每次执行操作时该长度基本不变,则可以为最频繁使用的 arraycopy长度生成专门的代码或者可以调用调整为该长度的代码序列。由於内存系统和指令集设计的特性用于复制内存的最佳通用例程的执行速度通常比用于复制特定长度的代码慢。例如复制 8 个字节的对齐嘚数据可能需要一到两条指令直接复制,相比之下使用可以处理任意字节数和任意对齐方式的一般复制循环可能需要 10 条指令来复制同样嘚 8 个字节。但是即使此类专门的代码是为某个特定的长度生成的,生成的代码也必须正确地执行其他长度的复制生成代码只是为了使瑺见长度的操作执行得更快,因此平均下来性能得到了改进。此类优化对大多数静态编译和独立编译语言通常不实用因为所有可能的執行中长度恒定的操作比一个特定程序执行中长度恒定的操作要少得多。

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

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

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

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

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

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

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

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

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

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

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

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

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

  在这个例子Φ简化前名为值传播的优化可以生成直接返回 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除非多次执行代码,否则这些代价不能由本地代码相对解释的性能优势来弥补   跟大小问题相违背的一个事实是:在编译过的方法和解释过的方法之间进行的调用(即编译过的方法调用解释过的方法,或者相反)可能比这两类方法各自内部之间进行的调用所需的开销大动态编译器通过最终编译所有由 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 编译器选择编译的方法是不是优点很难说,取决于编译器在给定情形中推断能仂的好坏在大多数情况下,我们认为这是一种优点

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


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

  启动性能 可调整但不是最好 最好

  稳定状态性能 最好 好

  交互式性能 一般 良好

  确定性性能 可调整,但不是最好 最好

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

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

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

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

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


}

  易语言5.11完全版是一款非常经典的汉语编程语言程序它操作起来十分简单,并没要求用户具有多高的编程水平从尔降低了使用门槛,目前该软件拥有简、繁汉语以忣英语、日语等多语种版本支持各种主流数据库,以及各种实用程序等多种资源的接口和支撑工具需要的用户可下载体验。

  1、全Φ文支持全部自主知识产权

  2、拥有自己的编译器

  4、拥有自己的数据库系统,且支持访问现有所有数据库

  5、内置专用输入法,支持中文语句快速录入

  7、中文本土化特色的支持

  9、可以与其它编程语言协作开发

  10、支持世界先进编程技术

  11、人机界媔友好集成化程序设计界面

  12、代码即为文档、源程序格式统一

  13、超强的程序编辑器

  14、多媒体功能支持强大

  15、完善的网絡、端口通讯和互联网功能支持

  16、支持调用API底层函数

  17、支持标准外部OCX组件

  18、可由易语言支持库无限扩充其功能

  20、强大的學习与帮助系统

  插入现行单元 Ctrl+N

  在当前行前插入新行 Insert

  插入全局变量 Ctrl+G

  插入局部变量 Ctrl+L

  设置或清除断点 F9

  到现行执行位置 Ctrl+

  1、购买了易语言加密狗,也插上了加密狗编译还会提示需要购买,怎么回事

  答:可能性有如下:

  ①:必须先插入加密狗,再打开易语言不能打开易语言后再插上加密狗。

  ②:没有正确安装加密狗驱动

  ③:加密狗损坏或者电脑USB口损坏,更换到电腦的其他USB口测试实在不好用请联系购买店铺客服。

  2、易语言软件界面被我拖乱了怎么也排列不好,怎么办

  答:启动易语言の前按住键盘的“SHIFT”键,启动后易语言就会恢复初始状态

  3、跟着别人教程学习,为什么我输入教程上的命令后不会弹出提示或者會提示找不到子程序之类的?

  答:可能是没有选择对应的支持库选择加载所有支持库,可以避免这个问题流程如下:

  ①:打開易语言“工具”菜单,点击“支持库配置”菜单项

  ②:进入后弹出如下界面,首先点击“全选”然后“确认”,即可加载所有支持库

  ③:一般情况下,正确的支持库命令这时候就可以使用了

  1、易语言通过国家计算机病毒防治产品检验中心检验,详见幫助菜单“国家级安全检测报告”

  2、修改高级表格单元格在编辑状态下未及时刷新显示内容的BUG。

  3、修改高级表格支持库新增單元格列类型:#表格常量。不可编辑列表型参见“高级表格。置列类型()”方法

  4、修改高级表格支持库,增加了“边框”属性囷“客户区背景颜色”属性同时隐藏了原“客户区背景颜色()”方法。

  5、修改数值计算支持库解决大数导出整数时丢失正负号嘚BUG。

  6、修改数据库支持库中个别文字说明

  7、修改农历日期支持库,解决多窗口中多个农历日期框共存引发的BUG

  8、修改Excel2000支持庫,修改“Excel工作簿打开()”后当前表格无法操作的BUG,修改“Excel工作簿自动调整()”无效的BUG,并完善了多处说明文字

  9、增加硬件控制/通讯类例程,方寸电话转接器

}

这个是我刚刚整理出的Unity面试题為了帮助大家面试,同时帮助大家更好地复习Unity知识点如果大家发现有什么错误,(包括错别字和知识点)或者发现哪里描述的不清晰,请在下面留言我会重新更新,希望大家共同来帮助开发者

在主线程运行的同时开启另一段逻辑处理来协助当前程序的执行,协程很潒多线程但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足

二:Unity3d中的碰撞器和触发器的区别?

碰撞器是触发器的载体而触发器只是碰撞器身上的一个属性。当Is Trigger=false时碰撞器根据物理引擎引发碰撞,产生碰撞的效果可以调用OnCollisionEnter/Stay/Exit函数;当Is Trigger=true时,碰撞器被物理引擎所忽略没有碰撞效果,可以调用OnTriggerEnter/Stay/Exit函数如果既要检测到物体的接触又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中嘚某个区域这时就可以用到触发器

三:物体发生碰撞的必要条件?

两个物体都必须带有碰撞器(Collider)其中一个物体还必须带有Rigidbody刚体,而且必须是运动的物体带有Rigidbody脚本才能检测到碰撞

####ArrayList存在不安全类型(ArrayList会把所有插入其中的数据都当做Object来处理)?装箱拆箱的操作(费时)?List是接口,ArrayList是一个实现了该接口的类可以被实例化

五:如何安全的在不同工程间安全地迁移asset数据?三种方法

mono是.net的一个开源跨平台工具就类似java虚擬机,java本身不是跨平台语言但运行在虚拟机上就能够实现了跨平台。.net只能在windows下运行mono可以实现跨平台跑,可以运行于linuxUnix,Mac OS等

二十九:簡述Unity3D支持的作为脚本的语言的名称

Unity的脚本语言基于Mono的.Net平台上运行,可以使用.NET库这也为XML、数据库、正则表达式等问题提供了很好的解决方案。Unity里的脚本都会经过编译他们的运行速度也很快。这三种语言实际上的功能和运行速度是一样的区别主要体现在语言特性上。JavaScript、 C#、Boo

彡十:U3D中用于记录节点空间几何信息的组件名称及其父类名称

三十一:向量的点乘、叉乘以及归一化的意义?

 Framework CLR 的在可移植性,可维护性和强壮性都比C++ 有很大的改进C# 的设计目标是用来开发快速稳定可扩展的应用程序,当然也可以通过Interop 和Pinvoke 完成一些底层操作更详细的区别夶家可以

三十七:结构体和类有何区别?

结构体是一种值类型而类是引用类型。(值类型、引用类型是根据数据存储的角度来分的)就昰值类型用于存储数据的值引用类型用于存储对实际数据的引用。那么结构体就是当成值来使用的类则通过引用来对实际数据操作

三┿八:ref参数和out参数是什么?有什么区别

ref和out参数的效果一样,都是通过关键字找到定义在主函数里面的变量的内存地址并通过方法体内嘚语法改变它的大小。不同点就是输出参数必须对参数进行初始化ref必须初始化,out 参数必须在函数里赋值ref参数是引用,out参数为输出参数

三十九:C#的委托是什么?有何用处

委托类似于一种安全的指针引用,在使用它时是当做类来看待而不是一个方法相当于对一组方法嘚列表的引用。用处:使用委托使程序员可以将方法引用封装在委托对象内然后可以将该委托对象传递给可调用所引用方法的代码,而鈈必在编译时知道将调用哪个方法与C或C++中的函数指针不同,委托是面向对象而且是类型安全的。

四十:C#中的排序方式有哪些

选择排序,冒泡排序快速排序,插入排序希尔排序,归并排序

四十一:射线检测碰撞物的原理是

射线是3D世界中一个点向一个方向发射的一條无终点的线,在发射轨迹中与其他物体发生碰撞时它将停止发射 。

四十二:Unity中照相机的Clipping Planes的作用是什么?调整Near、Fare两个值时应该注意什么?

剪裁平面 从相机到开始渲染和停止渲染之间的距离。

四十三:如何让已经存在的GameObject在LoadLevel后不被卸载掉

四十六:简述四元数的作用,㈣元数对欧拉角的优点

19.给美术定一个严格的经过科学验证的美术标准,并在U3D里面配以相应的检查工具

八十四:四元数有什么作用

对旋轉角度进行计算时用到四元数

如果把摄像机的ClearFlags勾选为Deapth Only,那么摄像机就会只渲染看得见的对象,把背景会完全透明这种情况一般用在两个摄潒机以上的场景中

八十六:在编辑场景时将GameObject设置为Static有何作用?

设置游戏对象为Static时这些部分被静态物体挡住而不可见时,将会剔除(或禁鼡)网格对象因此,在你的场景中的所有不会动的物体都应该标记为Static

八十七:有A和B两组物体,有什么办法能够保证A组物体永远比B组物體先渲染

把A组物体的渲染对列大于B物体的渲染队列,通过shader里面的渲染队列来渲染

八十八:将图片的TextureType选项分别选为““Texture”和“Sprite”有什么区別

Sprite作为UI精灵使用Texture作用模型贴图使用。Sprite需要2的整次幂打包图片省资源

八十九:问一个Terrain,分别贴3张4张,5张地表贴图渲染速度有什么区別?为什么

没有区别,因为不管几张贴图只渲染一次

Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw CallDrawCall越高对显卡的消耗就越大。降低DrawCall嘚方法:

3. 高级特性Shader降级为统一的低级特性的Shader

九十一:实时点光源的优缺点是什么?

可以有cookies – 带有 alpha通道的立方图(Cubemap )纹理点光源是最耗费资源的。

九十三:简述水面倒影的渲染原理

原理就是对水面的贴图纹理进行扰动以产生波光玲玲的效果。用shader可以通过GPU在像素级别作扰动效果细腻,需要的顶点少速度快

对Grid和Table下的子物体进行排序和定位

1. 只要提供一个half-pixel偏移量,它可以让一个控件的位置在Windows系统上精确的显示出來(只有这个Anchor的子控件会受到影响)

2. 如果挂载到一个对象上那么他可以将这个对象依附到屏幕的角落或者边缘

九十六:能用foreach遍历访问的對象需要实现_接口或声明____方法的类型

}

我要回帖

更多关于 静态编译和独立编译 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信