当前位置: 首页 > 后端技术 > Java

java的编译与执行

时间:2023-04-02 01:41:34 Java

编程语言分为低级语言和高级语言。机器语言和汇编语言是低级语言,而C、C++、java、python等是高级语言。机器语言是可以直接执行的最低级语言。而我们编写的源代码是人类语言,计算机只能识别某些特定的二进制指令,在程序真正运行之前必须将源代码转换成二进制指令。汇编语言由汇编程序翻译成机器指令,然后执行。一条汇编指令对应一条机器指令。高级语言程序设计程序有三种执行方式:1.一种是编译执行,源程序先由编译器翻译成机器指令(负责将源程序翻译成目标机器指令),然后编译-->link-->target然后执行可执行文件;即预先将所有源代码一次性转换为二进制指令,即生成可执行程序。比如C、C++等语言编译执行。2.一种是解释执行,就是用解释器把我们的一句话解释成机器可以识别的二进制代码来执行。它可以被认为是解释一个句子和执行一个句子。在此过程中,不会生成任何中间文件。例如:脚本模式是一系列命令,在执行过程中被系统解释器翻译成机器可识别的指令。比如shell脚本是由shell程序执行的,js是由浏览器解释执行的。.3、最后一个是编译与解释相结合。让我们谈谈Java。了解Java的几种编译器前端编译器:将.java文件转换成.class文件。包括Sun的Javac,EclipseJDT中的增量编辑器(ECJ),后端运行时即时编译器(JITcompiler,JustInTimeCompiler):将字节码转换成机器码。包括HotSpotVM的C1和C2编译器静态预编译器(AOT编译器,AheadOfTimeCompiler):将*.java编译成本地机器码。包括GNUCompilerfortheJava(GCJ),ExcelsiorJETJava采用了解释和编译的混合模式。在编译时,我们将源代码编译成.class,配合JVM的跨平台抽象,屏蔽了计算机底层操作系统与硬件的差异,实现了“一次编译,到处运行”。在运行期,目前主流的JVM是混合模式(-Xmixed),即解释和编译一起使用。Java最初的定位是一种“解释执行”的语言,但现在主流的虚拟机都包含了即时编译器JIT。程序从源代码到运行经历了几个阶段:java程序--(编译javac)-->字节码文件。(解释执行+JIT编译器编译)-->操作系统(Win、Linux、MacJVM)。.class文件是可以在任何地方运行的文件。然后将Java字节码转换成目标机器码,交由JVM执行,即Java的二次编译。Java采用解释编译混合模式:基于JVM执行引擎中解释器解释器和编译器JIT共存,由执行引擎获取,javac将源代码编译成字节码文件类。然后它在运行时被解释。解释器将其转换为最终的机器代码。(解释型)另外,JVM平台支持一种称为即时编译的技术。即时编译的目的是避免函数被解释执行,而是将整个函数体编译成机器码,可以大大提高执行效率(直接编译型)JIT将字节码转换成最终的机器码:以OracleJDK提供的HotSpot虚拟机为例。在HotSpot虚拟机中,提供了两种编译模式:解释执行和即时编译(JIT,Just-In-Time)。解释执行是将字节码一个一个地翻译成可运行的机器码,而即时编译是以方法为单位将字节码翻译成机器码(前文所说的“编译执行”)。前者的优点是无需等待,而后者在实际操作中效率更高。  即时编译之所以存在,是因为它是提高程序性能的重要手段之一。根据“第二十八定律”(即:20%的代码占用80%的系统资源),对于大部分不常用的代码,我们不需要花时间编译成机器码,但是使用解释器执行的方式是在使用的时候一一解释运行;对于一些只占一小部分的热代码(可以认为是重复执行的重要代码),可以将它们翻译成符合机器的机器码并高效执行,提高程序的效率,这正是-在运行时及时编译。  为了满足不同的场景,HotSpot虚拟机内置了多个即时编译器:C1、C2和Graal。Graal是Java10官方推出的实验性即时编译器,这里就不多描述了(其实我也不是很了解,囧。。。)。先来看看C1和C2,相信大家或多或少都接触过。C1:客户端编译器,面向对启动性能有要求的客户端GUI程序。采用的优化方式比较简单,所以编译时间比较短。C2:Server编译器,针对需要峰值性能的服务器端程序,采用了复杂的优化方法,因此编译时间长,但运行时性能较好。从Java7开始,H??otSpot虚拟机默认采用分层编译方式:hotspot方式先由C1编译器编译,然后hotspot方式中的hotspot由C2进一步编译,并根据计算出更好的编译优化之前的操作。为了不干扰程序的正常运行,JIT编译在一个额外的线程中执行,HotSpot根据实际CPU资源按1:2的比例分配C1和C2线程数。在计算机资源充足的情况下,字节码的解释和编译可以同时进行,JIT编译和执行后的机器码会在下次调用该方法时启动,取代了原来的解释和执行(意思是它被翻译成了更高效的机器码,自然而然地取代了原来相对低效的执行方式)。  以上,可以看出Java中不仅仅是解释执行,即时编译(compiledexecution)对Java的性能优化有着重要的作用,所以现在应该说:Java是解释执行的执行和编译执行并存,至少大部分是这样。编译还是解释?1、程序编译需要时间,移植到其他平台时需要重新编译,但编译后生成的可执行文件运行速度很快。2.解释型程序可以跨平台执行,不需要编译所有代码再运行,可以及时运行,但是因为是一个一个解释执行,所以最终运行速度不如编译型程式。3、内存占用:编译和执行需要生成编译后的机器码文件,而解释和执行是逐句执行,因此解释和执行占用内存较少。单独使用解释器的缺点:丢掉了JIT可能带来的性能优势。如果代码不是JIT编译的,再次运行时需要反复解析。单独使用JIT编译器的缺点:所有代码都需要编译成本地机器码。需要更多时间,JVM启动会慢很多;增加可执行代码的大小(字节码比JIT编译的机器码小得多),这将导致分页,从而使程序变慢。一些JIT编译器优化方法,例如分支预测,如果不进行分析,通常无法有效优化。因此,HotSpot采用惰性求值(LazyEvaluation)的方法。根据第28定律,只有一小部分代码(热代码)会消耗大部分系统资源,而这就是JIT需要编译的部分。JVM会根据每次执行代码的时间来收集信息,并相应地进行一些优化,因此执行的次数越多,速度就越快。JDK9引入了一种新的编译模式AOT(AheadofTimeCompilation),直接将字节码编译成机器码,从而避免了JIT预热等方面的开销。JDK支持分层编译和AOT协同使用。注意:JIT是在方法层面,它会将编译后的字节码缓存在CodeCache中,不会重复解释。