JVM学习笔记:逃逸分析的优化手段(猜想随笔)

简介: 逃逸分析:优化的内容只是针对那些未发生逃逸的对象,将对象通过标量替换的手段进行优化了,也就是说将未发生逃逸的对象拆分成了基础数据类型和方法,在栈帧使用栈帧即可管理。
有这样一个问题:对象是在堆中被分配的吗?我想说至少目前是这样的。

现在版本的JVM本身就已经默认开启逃逸分析来优化我们的代码,这种优化的思想有一种错觉是对象在栈上分配了,但其实并不是。实际上对象还是在堆中被分配的,优化的内容只是针对那些未发生逃逸的对象,将对象通过标量替换的手段进行优化了,也就是说将未发生逃逸的对象拆分成了基础数据类型方法,在栈帧使用栈帧即可管理,方法结束后栈帧出栈,“对象”被释放,减少了GC发生的次数,优化了代码。

为了巩固自己的印象,上文提到了这些名词,将在文中逐一介绍:

  1. 逃逸分析
  2. 什么叫未发生逃逸的对象
  3. 如何开启和关闭逃逸分析
  4. 标量替换是什么意思

示例代码

类名为StackAllocation。方法名:alloc,调用之后就new一个StackAllocation对象。main方法循环10000000次调用alloc方法,并且计算花费的时间。

public class StackAllocation {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        for (int i = 0;i < 10000000; i++){
            alloc();
        }

        long end = System.currentTimeMillis();
        System.out.println("花费的时间是:" + (end- start) + "毫秒");

        try {
            TimeUnit.SECONDS.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void alloc(){
        StackAllocation stackAllocation  = new StackAllocation();
    }
}

运行该代码时,添加JVM指令:-XX:-DoEscapeAnalysis(该命令是关闭逃逸分析),执行结果如下:

花费的时间是:75毫秒

那么我们开启逃逸分析:

花费的时间是:4毫秒

逃逸分析

逃逸分析的作用是用来减少Java程序中同步负载和内存堆分配的压力,它的基本行为就是分析对象作用域

未发生逃逸的对象

举个例子:当一个对象在A方法中被定义后,如果该对象仅在A方法中使用,则表示该对象是未发生逃逸的;

public void alloc(){
    Cheng c = new Cheng(); // 该对象c只在alloc方法中使用,未发生逃逸
}

发生逃逸的对象

而以下三种行为是会发生逃逸的:

  1. 为类成员赋值,我们常说的getInstance动作
public class EscapeAnalysis{
    private Cheng c;
    
    public void getInstance{
        this.c == null ? new Cheng():this.c; // 对象作用域已经出了这个方法
    }
}
  1. return语句
public Cheng getCheng(){
    return new Cheng(); // 对象作用域已经出了这个方法
}
  1. 调用return语句或者getInstance拿到已经发生逃逸的对象
public void run(){
    Cheng c = getInstance();
    c.run();
}

如何开启和关闭逃逸分析

开启:-XX:+DoEscapeAnalysis(默认就是开启的)

关闭:-XX:-DoEscapeAnalysis

标量替换是什么意思

标量是指一个无法再分解的数据,基本数据类型满足这个特征。

而类是由成员变量以及方法构成的,所以一般类成员是可以进行拆分,拆分成标量。这个拆有个前提就是满足未逃逸

例子:

private static void alloc() {
    Point point = new Point(1,2);
}
class Point {
    private int x;
    private int y;
}

point满足未逃逸,它将会优化成标量

private static void alloc() {
    int x = 1;
    int y = 2;
}

这种方法+变量的形式,用栈结构即可。

总结

如何理解逃逸分析呢?

第一步:我们要知道JVM放置对象和数组的地方称为GC垃圾回收的主要区域,如果频繁的GC操作是会影响程序性能的,所以目的是要减缓GC操作,这才有了逃逸分析。

第二步:了解逃逸分析做了什么事,它的设想是能不能栈上分配对象,如果可以对象的回收不由GC控制,用完直接出栈即可,满足这个就需要该对象是满足未逃逸的,只有它是未逃逸的前提下,就可以将该对象进行标量替换成标准数据类型和方法,这样的结构用栈帧就足以表示,从而间接的实现了栈上分配,而这里分配并不是将对象在栈上分配了,而是通过标量替换的方式用另一种方式在栈上表示了对象。

第三步:程序变快了的原因,就是通过第二步的方式,在栈中用出栈的方式管理对象的回收问题。

最后:逃逸分析并不成熟。

目录
相关文章
|
监控 Java Unix
6个Java 工具,轻松分析定位 JVM 问题 !
本文介绍了如何使用 JDK 自带工具查看和分析 JVM 的运行情况。通过编写一段测试代码(启动 10 个死循环线程,分配大量内存),结合常用工具如 `jps`、`jinfo`、`jstat`、`jstack`、`jvisualvm` 和 `jcmd` 等,详细展示了 JVM 参数配置、内存使用、线程状态及 GC 情况的监控方法。同时指出了一些常见问题,例如参数设置错误导致的内存异常,并通过实例说明了如何排查和解决。最后附上了官方文档链接,方便进一步学习。
3267 4
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
467 27
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
1387 166
|
监控 Java 编译器
聊聊JVM如何优化
JVM的优化是一个复杂而细致的过程,涉及内存管理、垃圾回收、即时编译、线程调度等多个方面。通过合理配置JVM参数、选择合适的垃圾回收器、优化线程调度和使用专业的监控工具,可以大幅提升Java应用的性能和稳定性。掌握这些优化技巧,能够帮助开发者在高并发、高负载的生产环境中保持系统的高效运行。
811 13
|
存储 设计模式 监控
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
412 0
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
|
监控 算法 Java
jvm-48-java 变更导致压测应用性能下降,如何分析定位原因?
【11月更文挑战第17天】当JVM相关变更导致压测应用性能下降时,可通过检查变更内容(如JVM参数、Java版本、代码变更)、收集性能监控数据(使用JVM监控工具、应用性能监控工具、系统资源监控)、分析垃圾回收情况(GC日志分析、内存泄漏检查)、分析线程和锁(线程状态分析、锁竞争分析)及分析代码执行路径(使用代码性能分析工具、代码审查)等步骤来定位和解决问题。
394 6
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
1070 55
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
1063 6
|
9月前
|
存储 缓存 Java
我们来说一说 JVM 的内存模型
我是小假 期待与你的下一次相遇 ~
582 5