Java面试题之关于JIT编译器的那些个优化项

简介: 目录一、关于解释器和编译器1、概述2、JIT(Just In Time)编译器二、JIT优化之锁粗化 & 锁消除三、JIT优化之逃逸分析 & 栈上分配 & 同步消除 & 标量替换1、概念描述2、逃逸分析代码示例3、逃逸分析失效示例四、JIT优化之方法内联(Inline Method)1、概述2、方法内联示例3、方法内联的优点

目录

一、关于解释器和编译器

1、概述

2、JIT(Just In Time)编译器

二、JIT优化之锁粗化 & 锁消除

三、JIT优化之逃逸分析 & 栈上分配 & 同步消除 & 标量替换

1、概念描述

2、逃逸分析代码示例

3、逃逸分析失效示例

四、JIT优化之方法内联(Inline Method)

1、概述

2、方法内联示例

3、方法内联的优点

一、关于解释器和编译器



1、概述

Java到底是一门解释型语言还是编译型语言呢?这取决于Java虚拟机,现在主流的商用虚拟机如HotSpot,都同时包含解释器与编译器,我们可以认为Java即是一门解释型语言,也是一门编译型语言。


关于解释器与编译器的优势:


解释器:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。

编译器:程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地机器码,获取更高的执行效率。


2、JIT(Just In Time)编译器

当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码“。为了提高热点代码的执行效率,虚拟机会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler)。


备注:为什么叫HotSpot虚拟机呢?字面意思就是热点虚拟机,其中的一部分功能就是会对热点代码进行优化。

二、JIT优化之锁粗化 & 锁消除



锁粗化锁消除都是针对synchronized平台级锁所做的优化,具体可参考:Java面试题之synchronized关键字原理以及锁相关

三、JIT优化之逃逸分析 & 栈上分配 & 同步消除 & 标量替换



1、概念描述

逃逸分析:所谓逃逸分析简单来说就是,分析创建的对象除了在线程栈中能访问,还能不能被其它线程线程所引用,用于确定创建的对象到底在堆中分配还是栈上分配。


栈上分配:我们都知道对象一般都是在堆上分配,如果逃逸分析发现对象只能在线程栈中访问,则会直接在栈上分配。


同步消除:如果逃逸分析发现一个变量无法被其它线程访问,那这个变量的读写就不会有竞争,对这个变量实施的同步措施也就可以消除掉。比如不保存对象头的Mark Word信息。


标量替换:把对象拆散,将其使用到的成员变量恢复原始类型来访问。如果逃逸分析发现对象只能在当前线程栈中可访问,且对象可以被拆散,那么程序可能不创建这个对象,而是直接在栈上分配成员变量。


备注:所谓标量是指一个数据已经无法再分解成更小的数据来表示了,比如原始数据类型等,都不能再分解,可以称之为标量。如果一个数据可以再分解,我们称作为聚合量,Java中的对象就是最典型的聚合量。

2、逃逸分析代码示例

@Data
class User {
 private Integer id;
 private String name;
}
/**
 * 关闭逃逸分析JVM参数:-XX:-DoEscapeAnalysis
 */
public class EscapeAnalysisExample {
 public static void createUser() {
  User user = new User();
  user.setId(1);
  user.setName("Nick");
 }
 public static void main(String[] args) {
  long start = System.currentTimeMillis();
  for (int count = 0; count < 1024 * 1024 * 50; count++) {
   createUser();
  }
  long end = System.currentTimeMillis();
  System.out.println("耗时为: " + (end - start) + " ms");
 }
}
  • 默认逃逸分析是开启的,运行程序的执行时间为:5ms
  • 加上虚拟机参数-XX:-DoEscapeAnalysis,关闭逃逸分析,运行程序的执行时间为:267ms

3、逃逸分析失效示例

@Data
class User {
 private Integer id;
 private String name;
 private List<String> hobbies = new ArrayList<>();
}


开启逃逸分析,当我们在User类中加上一行代码后,再次执行程序,发现程序执行时间又变成了277ms。

为什么程序的执行时间又会变慢呢?


我们都知道,线程栈的大小是有限的,由虚拟机参数-Xss决定。由于动态集合里无法确定有多少个对象,会占用多少内存,所以此时创建的对象是在堆上分配,而不是在栈上分配。


四、JIT优化之方法内联(Inline Method)



1、概述

关于方法内联的介绍我们在Java官方提供的文档里可以看到,运行时机器码生成器或者优化器会内联final修饰的方法,把方法调用替换成方法体里的代码。6d18aea07b29494ebb1ed0bb91e0f6d2.png

备注:官方文档地址可参考Java语言规范

疑问:是不是只有final方法才有可能在运行时优化被内联呢?


其实并不是的,final方法可以被内联是因为final方法不能被重写,在编译时即可以确定。

除了final方法,非虚方法可以直接被内联,这些方法可以在解析阶段确定唯一的版本。

遇到虚方法,如果该方法只有一个版本(Ps:由于多态可能会有多个版本),也可以进行内联。如果该方法有多个版本,使用内联缓存完成方法内联。

非虚方法定义:静态方法、私有方法、实例构造器、父类方法4类。


虚方法定义:实例方法都是虚方法。


备注:更多关于内联缓存的概念请参考周志明的《深入了解Java虚拟机第2版》。

2、方法内联示例

class Point {
 int x, y;
 void move(int dx, int dy) {
  x += dx;
  y += dy;
 }
}
/**
 * 方法内联示例
 * @author 刘亚楼
 * @date 2022/6/29
 */
public class MethodInlineExample {
 public static void main(String[] args) {
  Point[] points = new Point[1000];
  for (int count = 0; count < points.length; count++) {
   points[count] = new Point();
   points[count].move(count, points.length - 1 - count);
  }
 }
}

上面main方法里的代码会被替换成如下:

public static void main(String[] args) {
 Point[] points = new Point[1000];
 for (int count = 0; count < points.length; count++) {
  points[count] = new Point();
  points[count].x += count;
  points[count].y += points.length - 1 - count;
 }
}

我们都知道方法在调用时会创建一个栈帧(Stack Frame),栈帧中会保存局部变量表,操作数栈,方法出口等信息,每一个方法从调用到执行完成的过程,就代表着一个栈帧在虚拟机栈中入栈到出栈的过程。


通过方法内联,可以减少栈帧的创建,方法调用入栈和出栈的流程,提升程序运行效率。


相关文章
|
18小时前
|
存储 算法 搜索推荐
Java数据结构与算法优化
Java数据结构与算法优化
|
19小时前
|
监控 Java 数据库连接
Java中如何实现数据库连接池优化?
Java中如何实现数据库连接池优化?
|
19小时前
|
设计模式 Java 测试技术
Java中如何优化代码质量?
Java中如何优化代码质量?
|
1天前
|
缓存 算法 安全
Java中的数据结构与算法优化策略
Java中的数据结构与算法优化策略
|
1天前
|
SQL 缓存 Java
优化Java应用的数据库访问性能技巧
优化Java应用的数据库访问性能技巧
|
1天前
|
存储 NoSQL Java
探索Java分布式锁:在高并发环境下的同步访问实现与优化
【7月更文挑战第1天】在分布式系统中,Java分布式锁解决了多节点共享资源的同步访问问题,确保数据一致性。常见的实现包括Redis的SETNX和过期时间、ZooKeeper的临时有序节点、数据库操作及Java并发库。优化策略涉及锁超时、续期、公平性及性能。选择合适的锁策略对高并发系统的稳定性和性能至关重要。
11 0
|
1天前
|
存储 缓存 NoSQL
优化Java中网络通信的性能策略
优化Java中网络通信的性能策略
|
1天前
|
XML 缓存 JavaScript
优化Java中的XML解析性能
优化Java中的XML解析性能
|
1天前
|
XML JSON 缓存
优化Java中XML和JSON序列化
优化Java中XML和JSON序列化
|
1天前
|
SQL Java 数据库连接
Java中的数据库连接与优化
Java中的数据库连接与优化