最近因为公司的一些原因,我也开始学习一些 JAVA 的知识。虽然我一直是以 .NET 语言为主的程序员,但是我并不排斥任何其它语言。在此并不讨论 JAVA .NET 的好坏,仅仅是对 .NET 跟 JAVA 程序的编译执行过程进行一些简单的介绍跟比较。因为有些内容还是超出自己原来的认知的,所以整理一下做个记录。

.NET

.NET 程序的执行过程大概分以下几个步骤:

  1. 代码
  2. 语言编译器编译
  3. IL
  4. JIT 编译
  5. 运行

.NET 平台的程序编译的时候是分多步的。当我们写好代码开始编译的时候需要选择一个合适的编译器比如csc 、vbc 。经过这一次编译之后我们的程序会被打包成 dll

或者 .exe 文件。这些 dll 里面其实包含的是 MSIL 。IL 做为一种中间语言,为跨平台提供了基础。当我们把这些文件复制到目标机器上需要真正运行的时候,JIT (just-in-time compilation)编译开始工作了。CLR 为我们在每个支持的平台上都实现了一个 JIT 编译器,当一个方法在第一次运行的时候,JIT 编译会把 IL 编译成目标机器的机器码,这样我们的程序才能真正运行。这也是为什么 .NET 程序第一次运行的时候会慢一点的原因。解决这个问题我们可以使用工具 Ngen.exe 在第一次运行前进行一次预编译,这样就可以提升 .NET 程序的启动速度。

分层编译

上面大概描述了 .NET 程序编译过程。但是 JIT 编译可能还有一些特性需要讲一下,比如分层编译。

分层编译是从 .NET core 2.1 开始引入的一个特性。我们的 IL 到机器码,需要 JIT 进行一次编译,这会影响 .NET 程序的第一次运行的速度。微软为了解决这个问题引入了分层编译。分层编译把 JIT 编译分成两次。当一个方法第一次被执行的时候,JIT 编译器会进行第一次快速编译,这次编译并不会进行特别的优化操作,追求的是编译的速度。当我们的程序运行一段时间后,CLR 会自动感知到频繁运行的代码,这些代码被称为热点代码。当出现热点代码的时候 JIT 编译器会重新进行一次优化编译来提高热点代码的执行效率,从而提高整个程序的性能。

通过 JIT 分层编译, .NET 程序很好的在编译速度跟性能之间找到了平衡。

JAVA

JAVA 程序的执行过程大概分以下几个步骤:

  1. 代码
  2. 语言编译器编译
  3. 字节码
  4. 解释/JIT编译
  5. 运行

下面说说 JAVA 程序的编译过程。

当我们编写好 JAVA 程序,想要执行的时候,跟 .NET 程序一样,同样会选择一个语言编译器来进行第一次编译。因为 JVM 语言有好多种,比如 JAVA ,kotlin ,所以同样会有多种语言编译器,比如 javac,kotlinc 等等。这里还是以标准的 JAVA 为例,在语言编译器编译完源代码后,会生成一堆 .class 的文件,这些文件包含的内容被称之为字节码。字节码的存在跟 MSIL 类似,同样为跨平台提供了一种很好的方案。只要为每个平台实现接口一致的 JVM , 让这些 JVM 来运行字节码就可以跨平台了。

解释执行

当我们真正要执行 JAVA 程序的时候,这些字节码会被 JVM 执行。JVM 执行的时候首先会在 CodeCache 内查找这个方法有没有编译好的机器代码,如果没有那么交给“解释执行器”来解释执行。所谓解释执行,就是将代码一行行的经过解释器进行翻译成机器码后让目标机器执行。但是这些翻译的产物并不会被记录下来,也就是说同样的代码每次执行的时候都需要解释器进行翻译。

JIT 编译

显然对于一些重复执行的方法解释器执行效率会很低。为了解决这个问题,设计 JVM 的工程师们想出了办法。以 Hotspot 为例,当程序经过一段时间的解释执行后,JVM 会记录这些方法的执行次数,当一些方法反复被执行的时候,JVM 会认为这些方法是热点代码。这时候 JVM 会对这些热点代码进行一次 JIT 编译,这次 JIT 编译还会根据运行时的 profile 进行优化。编译完成后把 JIT 编译的产物固定下来,存储在 CodeCache 中。这样当一个方法下次再次被执行的时候 JVM 会从 CodeCache 中直接读取机器码来执行。这样热点代码的执行效率就会大大的提供,这也是为啥有些 JAVA 程序需要进行预热。

总结

通过以上我们分别描述了 .NET 跟 JAVA 程序编译执行的过程。他们之间的区别在于 .NET 程序不管什么时候都是进行 JIT 编译,并且通过分层编译技术在首次执行速度跟性能之间找到了平衡。而 JAVA 虽然做为一门静态语言,但是它的代码一开始竟然是解释执行的(当然这是对 Hotspot JVM而言的,有的 JVM 未必是这样),在运行的时候才会对热点代码进行 JIT 编译优化代码。虽然大家实现的方式不同,但是殊途同归,都是通过对热点代码的二次编译实现了对程序的性能的优化。

参考

https://docs.microsoft.com/zh-cn/dotnet/standard/managed-execution-process

https://www.zhihu.com/question/37389356/answer/73820511

关注我的公众号一起玩转技术

关于 .NET 与 JAVA 在 JIT 编译上的一些差异的更多相关文章

  1. 你的java 代码对JIT编译友好吗?

    JIT编译器是Java虚拟机(以下简称JVM)中效率最高并且最重要的组成部分之一.但是很多的程序并没有充分利用JIT的高性能优化能力,很多开发者甚至也并不清楚他们的程序有效利用JIT的程度. 在本文中 ...

  2. 你的Java代码对JIT编译友好么?(转)

    JIT编译器是Java虚拟机(以下简称JVM)中效率最高并且最重要的组成部分之一.但是很多的程序并没有充分利用JIT的高性能优化能力,很多开发者甚至也并不清楚他们的程序有效利用JIT的程度. 在本文中 ...

  3. 【深入Java虚拟机】之七:Javac编译与JIT编译

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/18009455 编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理 ...

  4. Java虚拟机 - Javac编译与JIT编译

    [深入Java虚拟机]之七:Javac编译与JIT编译 编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤 ...

  5. 深入理解java虚拟机(十三) Java 即时编译器JIT机制以及编译优化

    在部分的商用虚拟机中,Java 程序最初是通过解释器( Interpreter )进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为“热点代码”.为了提高热点代码的 ...

  6. Java 面试-即时编译( JIT )

    当我们在写代码时,一个方法内部的行数自然是越少越好,这样逻辑清晰.方便阅读,其实好处远不止如此,通过即时编译,甚至可以提高执行时的性能,今天就让我们好好来了解一下其中的原理. 简介 当 JVM 的初始 ...

  7. 90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(1)- JIT编译优化

    麻烦大家帮我投一票哈,谢谢 经常听到 Java 性能不如 C/C++ 的言论,也经常听说 Java 程序需要预热,那么其中主要原因是啥呢? 面试的时候谈到 JVM,也有很多面试官喜欢问,为啥 Java ...

  8. 【Java】实战Java虚拟机之五“开启JIT编译”

    今天开始实战Java虚拟机之五“开启JIT编译” 总计有5个系列 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Ja ...

  9. javac 编译与 JIT 编译

    编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤进行: 其中绿色的模块可以选择性实现.很容易看出,上图中 ...

随机推荐

  1. JUC下工具类CountDownLatch用法以及源码理解

    CountDownLoatch是JUC下一个用于控制计数的计数器,比如我需要从6开始计数,每个线成运行完之后计数减一,等计数器到0时候开始执行其他任务. public static void main ...

  2. linux远程和软件包的管理

    远程管理 ssh   用户名@对方IP地址 -X   在本地可以运行对方的图形程序 端口 22 [root@room9pc01 ~]# ssh root@172.25.0.11 [root@serve ...

  3. NX二次开发】Block UI 选择特征

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  4. 第三节:Redis缓存雪崩、击穿、穿透、双写一致性、并发竞争、热点key重建优化、BigKey的优化 等解决方案

    一. 缓存雪崩 1. 含义 同一时刻,大量的缓存同时过期失效. 2. 产生原因和后果 (1). 原因:由于开发人员经验不足或失误,大量热点缓存设置了统一的过期时间. (2). 产生后果:恰逢秒杀高峰, ...

  5. 重磅!GitHub官方开源新命令行工具

    近日,GitHub 发布命令列工具 (Beta) 测试版,官方表示,GitHub CLI提供了一种更简单.更无缝的方法来使用Github.这个命令行工具叫做GitHub CLI,别名gh. 现在,你就 ...

  6. XML从入门到深入(超详细)

    一:什么是XML XML (eXtensible Markup Language)指可扩展标记语言,标准通用标记语言的子集,简称XML.是一种用于标记电子文件使其具有结构性的标记语言. XML可以标记 ...

  7. 基于ABP落地领域驱动设计-03.仓储和规约最佳实践和原则

    目录 系列文章 仓储 仓储的通用原则 仓储中不包含领域逻辑 规约 在实体中使用规约 在仓储中使用规约 组合规约 学习帮助 围绕DDD和ABP Framework两个核心技术,后面还会陆续发布核心构件实 ...

  8. OpenResty高并发

    在电商项目中所有的访问都是通过首页访问进去的,那么首页门户的访问频率会是非常高的,用我们专业术语来说就是并发量高,这时问题就来了,并发量高我们在做程序时就要保证首页的抗压能力强,而且还要保证抗压的同时 ...

  9. YOLO V4的模型训练

    1.YOLO V4模型训练的基本思路 所有机器学习涉及模型训练,一般都有训练集.验证集.测试集,因此需要准备数据集.有了数据集,再调用训练的算法,获取训练的结果.v3.v4模型训练方法相同. 2.YO ...

  10. 《吃透微服务》 - 服务容错之Sentinel

    大家好,我是小菜. 一个希望能够成为 吹着牛X谈架构 的男人!如果你也想成为我想成为的人,不然点个关注做个伴,让小菜不再孤单! 本文主要介绍 SpringCloud中Sentinel 如有需要,可以参 ...