JIT、逃逸分析、锁消除、栈上分配和标量替换等都属于 JVM 的优化手段,JVM 优化手段是指在运行 Java 程序时,通过对字节码的编译和执行过程进行优化,以提升程序的性能和效率。

JVM 优化手段主要有以下几个:

  1. JIT(Just-In-Time,即时编译):是一种在程序运行时将部分热点代码编译成机器代码的技术,以提高程序的执行性能的机制。
  2. 逃逸分析:用于确定对象动态作用域是否超过当前方法或线程,通过逃逸分析,编译器可以决定一个对象的作用范围,从而进行相应的优化,但确定对象没有逃逸时,可以进行以下优化:
    1. 栈上分配:如果编译器可以确定一个对象不会逃逸出方法,它可以将对象分配在栈上而不是堆上。在栈上分配的对象在方法返回后就会自动销毁,不需要进行垃圾回收,提高了程序的执行效率。
    2. 锁消除:如果对象只在单线程中使用,那么同步锁可能会被消除,提高程序性能。
    3. 标量替换:将原本需要分配在堆上的对象拆解成若干个基础数据类型存储在栈上,进一步减少堆空间的使用。
  3. 字符串池(String Pool)优化:JVM 通过共享字符串常量,重用字符串对象,以减少内存占用和提升字符串操作的性能。

1.JIT优点和热点代码

JIT 优点包含以下两个:

  1. 性能优化:由于编译成本地机器代码,程序的执行速度通常比解释性执行或预编译的代码要快得多。
  2. 平台无关性:JIT 编译器可以根据不同的硬件平台生成不同的机器代码,使得相同的程序可以在不同的计算机上运行,而无需重新编写。

什么是热点代码?

在 HotSpot 虚拟机中,热点代码(Hot Code)是指那些被频繁执行的代码。

热点代码的执行次数在不同的 JDK 版本和不同的 JVM 中是不同的,例如,它在 JDK 21 Client 模式下为 1500 次,Server 模式下为 10000 次,这个值可以通过 JVM 参数设置。

通常来说,热点代码的识别基于以下两种策略:

  1. 方法调用次数:当一个方法被调用一定次数后,会被视为热点代码并触发即时编译。这个次数在不同 JDK 版本中可能有所变化,并且可以通过 JVM 参数 -XX:CompileThreshold 进行设置。
  2. 回边计数:对于循环体等热点区域,通过统计从循环体返回到循环条件检查点的次数(即回边次数),达到一定次数也会触发即时编译。同样,这个阈值也可以通过 JVM 参数 -XX:OnStackReplacePercentage 进行设置。回边计数器有一个计算公式【回边计数器阈值=方法调用计数器阈值 * (OnStackReplacePercentage - InterpreterProfilePercentage)】,通过计算,在 JDK 21 Server 模式下,虚拟机回边计数器的阈值为 10700【10000*(140-33)】。

可以使用 java -XX:+PrintFlagsFinal -version 命令查看 JVM 默认配置。

2.栈上分配 VS 标量替换

栈上分配和标量替换是编译器的两种优化技术,它们虽然有一些相似之处,但并不完全相同。

  • 栈上分配(Stack Allocation):一种优化技术,它将对象分配在栈上而不是堆上。这种技术适用于编译器可以确定对象不会逃逸出方法,并且对象的生命周期在方法内部结束的情况。通过在栈上分配对象,可以避免在堆上进行内存分配和垃圾回收的开销,从而提高程序的性能和内存使用效率。
  • 标量替换(Scalar Replacement):与栈上分配类似,也是一种优化技术。它将一个复杂对象拆分成独立的成员变量,使其成为基本类型或基本类型数组的局部变量。这种技术适用于编译器可以确定对象的成员变量不会逃逸的情况。标量替换可以提供更细粒度的控制,使得编译器可以对独立的成员变量进行更精细的优化,例如寄存器分配和代码优化。

也就是说栈上分配,只是将对象从堆上分配到栈上了;而标量替换是更进一步的优化技术,将对象拆解成基本类型分配到栈上了。

2.1 锁消除代码演示

锁消除(Lock Elimination)也叫做同步消除,是一种编译器优化技术,它可以消除对于变量的不必要的锁定操作。锁消除的目的是减少锁的开销,提高程序的性能。

例如以下代码:

public void method() {
Object lock = new Object();
synchronized(lock){
System.out.println("www.javacn.site");
}
}

而锁消除之后的代码如下:

public void method(){
System.out.println("www.javacn.site");
}

2.2 标量替换代码演示

未优化前的代码如下:

private static class Point {
private int x;
private int y;
}
public static void main(String[] args) {
Point point = createPoint(10, 20);
int sum = point.x + point.y;
System.out.println("Sum: " + sum);
}
private static Point createPoint(int x, int y) {
Point point = new Point();
point.x = x;
point.y = y;
return point;
}

标量替换优化后的代码如下:

public static void main(String[] args) {
int x = 10;
int y = 20;
int sum = x + y;
System.out.println("Sum: " + sum);
}

通过逃逸分析的优化能够减少垃圾回收的压力、减少内存分配和释放带来的性能损耗,并且有可能减少对锁的依赖,以及实现标量替换等,从而整体上提升了应用程序的运行效率。

课后思考

Java 为什么不把所有代码提前都编译成二进制的机器码呢?这样岂不是运行更快?新 Java 虚拟机 GraalVM 中的 AOT 和 JIT 又有什么区别呢?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?的更多相关文章

  1. 面试官问我,Redis分布式锁如何续期?懵了。

    前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...

  2. 面试官问我“Java中的锁有哪些?以及区别”,我跪了

    在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分段锁 偏向锁/轻量级 ...

  3. 如果面试官问你 JVM,额外回答逃逸分析技术会让你加分!

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章. 引言 我在面试别人的过程中,JVM 内存模型我几乎必问,虽然有人说问这些就是面试造航母,工作 ...

  4. 面试官:Java中对象都存放在堆中吗?你知道逃逸分析?

    面试官:Java虚拟机的内存分为哪几个区域? 我(微笑着):程序计数器.虚拟机栈.本地方法栈.堆.方法区 面试官:对象一般存放在哪个区域? 我:堆. 面试官:对象都存放在堆中吗? 我:是的. 面试官: ...

  5. 阿里面试官:小伙子,你给我说一下JVM对象创建与内存分配机制吧

    内存分配机制   逐步分析 类加载检查: 虚拟机遇到一条new指令(new关键字.对象的克隆.对象的序列化等)时,会先去检查这个指令的参数在常量池中定位到一个类的符号引用,并且这个符号引用代表的类是否 ...

  6. JIT对锁的优化- 锁消除和锁粗化案例分析

    锁消除和锁粗化案例分析 锁消除 直接上代码 /** * 描述: 锁粒度演示 * @author karl * @create 2020-02-11 14:38 */ public class MySy ...

  7. 面试官:JVM锁优化都优化了啥?

    从JDK1.6开始,JVM对锁进行了各种优化,目的就是为了在线程间更高效的共享数据和解决互斥同步的问题.从锁优化的话题开始,可以引申出很多考点面试题,比如锁优化的技术.各优化技术的细节.CAS实现原理 ...

  8. 面试问我 Java 逃逸分析,瞬间被秒杀了。。

    记得几年前有一次栈长去面试,问到了这么一个问题: Java中的对象都是在堆中分配吗?说明为什么! 当时我被问得一脸蒙逼,瞬间被秒杀得体无完肤,当时我压根就不知道他在考什么知识点,难道对象不是在堆中分配 ...

  9. 面试官问我JVM调优,我忍不住了!

    面试官:今天要不来聊聊JVM调优相关的吧? 面试官:你曾经在生产环境下有过调优JVM的经历吗? 候选者:没有 面试官:... 候选者:嗯...是这样的,我们一般优化系统的思路是这样的 候选者:1. 一 ...

  10. 【性能优化】面试官:Java中的对象都是在堆上分配的吗?

    写在前面 从开始学习Java的时候,我们就接触了这样一种观点:Java中的对象是在堆上创建的,对象的引用是放在栈里的,那这个观点就真的是正确的吗?如果是正确的,那么,面试官为啥会问:"Jav ...

随机推荐

  1. Python 3.12 抢先看——关于 f-string 的改动

    Python 3.12 抢先看--关于 f-string 的改动 哈喽大家好,我是咸鱼 相信小伙伴们对 python 中的 f-string 都不陌生 f-string 是格式化字符串的缩写,是以小写 ...

  2. 路径规划之 A* 算法

    算法介绍 A*(念做:A Star)算法是一种很常用的路径查找和图形遍历算法.它有较好的性能和准确度.本文在讲解算法的同时也会提供Python语言的代码实现,并会借助matplotlib库动态的展示算 ...

  3. AtCoder Beginner Contest 182 Person Editorial

    Problem A - twiblr 直接输出 \(2A + 100 - B\) Problem B - Almost GCD 这里暴力枚举即可 int main() { ios_base::sync ...

  4. 双非本科拿下oppo sp!这位粉丝太强了!

    哈喽,大家好,我是仲一.今天分享的是一位双非本科生拿下oppo sp的秋招经验.当时,这位粉丝咨询我offer选择的时候,看到年薪31W这个数字,我以为他是研究生.后来,再三确认了,他确实是本科生. ...

  5. C# 几种常见数据结构(数组、链表、Hash表)

    一.内存上连续存储,节约空间,可以索引访问,读取快,增删慢 Array: 在内存上连续分配的,而且元素类型是一样的,可以坐标访问;读取快--增删慢,长度不变 { //Array:在内存上连续分配的,而 ...

  6. 文心一言 VS 讯飞星火 VS chatgpt (184)-- 算法导论13.5 1题

    一.用go语言,对于图14-1中的红黑树 T,说明执行 OS-SELECT(T.root,10)的过程. 文心一言: 在红黑树中,OS-SELECT 是一个用于在树中查找特定键值的操作.给定一个红黑树 ...

  7. 有n个整数,使前面各数顺序向后m个位置,最后m个数变成最前面m个数,见图 8.43。写一函数实现以上功能在主函数中输入个整数和输出调整后的n个数。

    4,有n个整数,使前面各数顺序向后m个位置,最后m个数变成最前面m个数,见图 8.43.写一函数实现以上功能在主函数中输入个整数和输出调整后的n个数. 我的代码: 1.使用双向链表 void Move ...

  8. [转帖]TPC-C 、TPC-H和TPC-DS区别

    https://zhuanlan.zhihu.com/p/339886289 针对数据库不同的使用场景TPC组织发布了多项测试标准. TPC-C: TPC Benchmark C于1992年7月获得批 ...

  9. Raid卡型号的简单辨认与问题发现过程

    Raid卡型号的简单辨认与问题发现过程 背景 同事给了一个awr报告. !-_-! 其实我看不懂. 但是他告诉我 有大量的log file sync 的等待事件. 然后又给了一套其他的文件, 发现lo ...

  10. [转帖]编译安装goofys挂载Scaleway免费75G对象存储

    日常•2022年5月29日   goofys编译 goofys是一个开源的使用Go编写的s3存储桶挂载工具,主打高性能.由于使用Go编写,没有用到什么特别的依赖,自己编译也很容易.截止2022.5.2 ...