逃逸分析和标量替换技术,你明白了吗

简介: 逃逸分析和标量替换技术,你明白了吗


逃逸分析

逃逸分析是目前JVM中比较前沿的优化技术,它不是直接的优化手段而是为其他优化手段提供依据的分析技术 逃逸分析的基本行为就是分析对象动态作用域。

逃逸分析是一种分析技术,分析对象的动态作用域,供其他优化措施提供依据。比如分析一个对象不会逃逸到方法之外或线程之外,其它优化措施(栈上分配,标量替换等)根据逃逸程度进行优化。

小编吐槽: 逃逸分析只是分析,不干事,jvm根据逃逸分析后的结果,决定采取什么方式对我们的代码进行优化。

如果分析后得到的结果是: 对象没有逃逸,大白话就是 方法中的 对象没有 传递到方法之外。jvm可以我们进行优化了。

public class EscapeAnalysis {
  public Person p;
  /**
   * 发生逃逸,对象被返回到方法作用域以外,被方法外部,线程外部都可以访问
   */
  public void escape(){
    p = new Person(26, "TomCoding escape");
  }
  /**
   * 不会逃逸,对象在方法内部
   */
  public String noEscape(){
    Person person = new Person(26, "TomCoding noEscape");
    return person.name;
  }
}
static class Person {
  public int age;
  public String name;
  ... // 省略构造方法
}

怎么做逃逸分析后的优化?

jvm自动会为我们做逃逸分析优化,它这么厉害,做了哪些优化呢?

其实,hotspot虚拟机为我们默认开启了三组jvm参数。分别是:

-XX:+DoEscapeAnalysis:启用逃逸分析(默认打开)

-XX:+EliminateAllocations:标量替换(默认打开)

-XX:+UseTLAB 本地线程分配缓冲(默认打开)

小编吐槽,只要不手残,jvm就可以为我们做逃逸分析后的优化。

什么是线程分配缓冲TLAB?

TLAB的目的是在为新对象分配内存空间时,让每个Java应用线程能在使用自己专属的分配指针来分配空间(Eden区,默认Eden的1%),减少同步开销。

即每个线程在Java堆中预先分配一小块私有内存,也就是本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),如果设置了虚拟机参数 -XX:+UseTLAB,在线程初始化时,同时也会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个Buffer,如果需要分配内存,就在自己的Buffer上分配,这样就不存在竞争的情况,可以大大提升分配效率,当Buffer容量不够的时候,再重新从Eden区域申请一块继续使用。

TLAB只是让每个线程有私有的分配指针,但底下存对象的内存空间还是给所有线程访问的(类似于堆),只是其它线程无法在这个区域分配而已。当一个TLAB用满(分配指针top撞上分配极限end了),就新申请一个TLAB。

小编吐槽: 这种方式是在在堆中给每个线程分配一个内存。每个线程操作单独的区域,用了再分配新的区域,这里也得用到同步方案。不过这种方式是提前分配缓冲池,至于不够的时候申请新的内存才加锁,减少了锁的次数,优化了每次都要加锁的性能问题。

这篇文章写了TLAB是多线程环境下 栈分配内存的一种优化方式。

推荐下:逃逸分析与tlab

什么是标量替换?

标量可以理解成一种不可分解的变量,如java内部的基本数据类型、引用类型等。

与之对应的聚合量可以被拆解的,如对象。

当通过逃逸分析一个对象只会作用于方法内部,虚拟机可以通过使用标量替换来进行优化。

比如上述noEscape()方法中person对象只会在方法内部,通过标量替换技术得到如下伪码:

/**
 * 不会逃逸,对象在方法内部
 */
public String noEscape(){
  int age = 26;
  String name = "TomCoding noEscape";
  return name;
}

完整的测试例子推荐这个文章

https://www.jb51.net/article/196801.htm

实战

我们可以手动关闭和开始逃逸分析.

开始逃逸分析(默认开启的)

public class StackAlloc {
  public static class User{
    public int id = 0;
    public String name = "";
  }
  public static void alloc() {
    User u = new User();  //Object  在堆上分配的() ,有逃逸分析的技术 ,在栈中分配的
    u.id = 5;
    u.name = "Jack Ma";
  }
  public static void main(String[] args) {
    long b = System.currentTimeMillis(); //开始时间
    for(int i=0;i<100000000;i++) {//一个方法运行1亿次()
      alloc();
    }
    long e = System.currentTimeMillis(); //结束时间
    System.out.println(e-b);//打印运行时间:毫秒
  }
}

来看下我们的方法运行效果:

因为默认开启了上面的3组命令 只开启如下命令:-XX:+PrintGC

我们先运行看看:

我们运行了一亿次方法(分配对象): 用时6毫秒

关闭逃逸分析-XX:-DoEscapeAnalysis

运行结果:

小编吐槽,为啥开启逃逸分析后,分析到没有逃逸就没有发生gc呢?

由于栈的结构原因,当栈进行出栈操作的时候,就会将这一部分内存回收。如果在方法调用中,频繁出现内存分配,在方法结束时候对象即可以销毁,这时候考虑可以在栈上分配内存,减少堆内存的回收压力。

在栈上进行内存分配,需要知道这部分内存不会在外部进行访问(-XX:+DoEscapeAnalysis)同时对于其中的对象进行分解,使用标量进行替换(-XX:+EliminateAllocations)。



相关文章
|
机器学习/深度学习 编解码
ICCV2023 | SRFormer:基于置换自注意力的图像超分辨率
ICCV2023 | SRFormer:基于置换自注意力的图像超分辨率
685 0
|
Python
Python无限弹窗表白完整代码
Python无限弹窗表白完整代码
303 0
创建asm disk 磁盘组出错! ORA-15018 And ORA-15107 (Doc ID 2678808.1)
ORA-15018: diskgroup cannot be created ORA-15107: missing or invalid ASM disk name
263 0
|
Android开发
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
1872 0
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
|
计算机视觉
数据集学习笔记(三):COCO创建dataloader用于训练
如何使用COCO数据集创建dataloader进行训练,包括安装环境、加载数据集代码、定义数据转换、创建数据集对象以及创建dataloader。
314 5
|
8月前
|
弹性计算 安全 Linux
阿里云服务器镜像解析:镜像类型对比、适用场景与选择策略参考
阿里云服务器镜像,作为ECS实例的“装机盘”,不仅提供了操作系统,还包含了初始化应用数据和预装软件,云服务器镜像的选择对于云服务器的性能和稳定性起着至关重要的作用,选择合适的镜像对于云服务器的性能和稳定性至关重要。本文将深入解析阿里云服务器提供的多种镜像类型,从公共镜像到社区镜像,全面介绍每种镜像的特点、优势以及选择建议,帮助用户根据自身需求做出适合自己的选择。
1125 12
|
机器学习/深度学习 算法 数据挖掘
YOLO系列算法
8月更文挑战第13天
|
9月前
|
SQL 关系型数据库 MySQL
milvus-use教程 python
本项目参考vanna项目,获取数据库元数据和问题SQL对,存入Milvus向量数据库,并进行相似性检索。采用m3e-large嵌入模型,通过DatabaseManager类实现数据库连接持久化,MilvusVectorStore类封装了Milvus操作方法,如创建集合、添加数据和查询。项目提供init_collections、delete_collections等文件用于初始化、删除和管理集合。所用Milvus版本较新,API与vanna项目不兼容。 [项目地址](https://gitee.com/alpbeta/milvus-use)
|
9月前
|
机器人 数据安全/隐私保护
基于PID控制器的六自由度串联机器人控制系统的simulink建模与仿真
本课题基于MATLAB2022a的Simulink环境,对六自由度串联机器人控制系统进行建模与仿真,采用PID控制器实现关节的位置、速度或力矩控制。PID控制器通过比例、积分、微分三种策略有效减小系统误差,提高响应速度和稳定性。仿真结果显示系统运行良好,无水印。尽管PID控制简单实用,但在复杂动力学环境下,常结合其他控制策略以增强鲁棒性。
|
12月前
|
数据采集 Web App开发 监控
Python爬虫:爱奇艺榜单数据的实时监控
Python爬虫:爱奇艺榜单数据的实时监控