专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

8 即时编译

ins518 2025-02-09 12:35:01 技术文章 27 ℃ 0 评论

我们先了解java编译相关的几个概念


前端编译


java编译器(javac)把源文件(.java)编译成java字节码(.class)文件的步骤叫前端编译


解释编译


在JVM加载class文件的字节码后,每次执行方法调用的时候,JVM会把字节码翻译成机器码,然后CPU再执行机器码,这个过程叫解释执行。

解释执行为了提升启动效率,并没有在启动时将字节码全部翻译成机器码,所以启动效率较高。

但是在执行过程中,字节码不能被执行,要翻译成机器码才能执行,所以执行效率会比较低。


编译执行


编译执行和解释执行相反,JVM在加载字节码的时候直接翻译成机器码,在执行程序的时候直接执行机器码。

同理,编译执行在启动的时候比较慢在执行的时候效率比较高。


即时编译


那么JVM如何实现启动效率和执行效率都高呢?

JVM又是怎么知道哪些代码需要解释执行哪些代码需要编译执行呢?这个时候提出了热点代码的概念,JVM会对热点代码进行编译执行。


JVM是如何判断什么是热点代码的呢?如果JVM发现某个方法或代码块被频繁执行的时候,会认为这是热点代码。然后JIT会把部分热点代码翻译成本地的机器码,并把编译机器码缓存起来。

这个缓存起来的机器码叫做:code cache。当JVM下次遇到相同热点代码的时候直接从code cache中拿到机器码直接执行。这样就达到了在实际的代码执行中编译的操作叫即时编译。


架构师的视角: JVM的缓存架构


code cache做了机器码的缓存,我们在做大型的互联网平台的时候也是存在大量的缓存设计。比如热搜的预热,频繁使用的数据的缓存策略(数据一致性的问题)。

我们再看看操作系统磁盘的热点数据缓存到内存的策略,CPU的缓存策略,这些都是相通的。


我们这里先说基础,在后续的文章中会谈到设计理念。我们接着聊JVM的话题


即时编译器的种类


JVM包含多个即时编译器,主要有C1和C2,还有个Graal (实验性的)。

多个即时编译器, 都会对字节码进行优化并生成机器码。

但是不同的即时编译器,优化的程度不同:C1会对字节码进行简单可靠的优化,C2会对字节码进行激进优化。

C1会对字节码进行简单可靠的优化,包括方法内联、去虚拟化、冗余消除等,编译速度较快,可以通过-client强制指定C1编译

C2会对字节码进行激进优化,包括分支频率预测、同步擦除等,可以通过-server强制指定C2编译,如果没有强制指定,JVM默认会使用分层编译模式。


分层编译模式


JVM不会直接启用C2,而是先通过C1编译收集程序的运行状态,再根据分析结果判断是否启用C2。

分层编译模式下, 虚拟机执行状态由简到繁、由快到慢分为5层

0 层,解释执行(Interpreter)

1 层,使用 C1 即时编译器编译执行,无profiling

2 层,使用 C1 即时编译器编译执行,带基本的 profiling(仅方法调用次数及循环回边执行次数的profiling)

3 层,使用 C1 即时编译器编译执行,带完全的 profiling

4 层,使用 C2 即时编译器编译执行


由于篇幅有限,具体的处理细节这里不进行熬述。计算机类的书籍很多,扣技术细节我们的精力也不够用。读计算机类的书或者说技术类的书,我们把大框架读懂就可以了,在工作和生活中遇到具体的问题再去查阅资料是最有效的一种方式。如果朋友们有兴趣我会单独搞一个如何读书的话题。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表