【18】逃逸分析

一、逃逸分析

概念:一种确定指针动态范围的静态分析,它可以分析在程序的哪些地方可以访问到指针

Java 虚拟机中的逃逸分析针对的是新建对象

即时编译器判断对象是否逃逸的依据:
1.对象是否被存入堆中(静态字段或者堆中对象的实例字段)
2.对象是否被传入未知代码中


public void forEach(ArrayList<Object> list, Consumer<Object> f) {
  Itr iter = new Itr; // 注意这里是new指令
  iter.cursor = 0;
  iter.lastRet = -1;
  iter.expectedModCount = list.modCount;
  while (iter.cursor < list.size) {
    if (list.modCount != iter.expectedModCount)
      throw new ConcurrentModificationException();
    int i = iter.cursor;
    if (i >= list.size)
      throw new NoSuchElementException();
    Object[] elementData = list.elementData;
    if (i >= elementData.length)
      throw new ConcurrentModificationException();
    iter.cursor = i + 1;
    iter.lastRet = i;
    Object obj = elementData[i];
    f.accept(obj);
  }
}

新建的ArrayList$Itr实例既没有被存入任何字段之中,也没有作为任何方法调用的调用者或者参数。因此,逃逸分析将断定该实例不逃逸。

二、基于逃逸分析的优化

即时编译器可以根据逃逸分析的结果进行诸如锁消除、栈上分配以及标量替换的优化。

锁消除

锁对象不逃逸就意味着该锁对象的加、解锁都没有意义。
即时编译器可以消除对该不逃逸锁对象的加锁、解锁操作

synchronized (new Object()) {}会被完全优化掉。这正是因为基于逃逸分析的锁消除。由于其他线程不能获得该锁对象,因此也无法基于该锁对象构造两个线程之间的 happens-before 规则

栈上分配

(1)若不使用逃逸分析技术,对象创建方式:
JVM对象都是在堆上分配的,堆上的内容对任何线程可见,JVM需要对所分配的堆内存进行管理。

需要借助垃圾回收器来处理不再被引用的对象。

(2)若使用逃逸分析技术,对象创建方式:

逃逸分析证明新建对象不可逃逸之后:
若证明某些新建的对象不逃逸,JVM可以将其分配至栈上,并且在 new 语句所在的方法退出时,通过弹出当前方法的栈桢来自动回收所分配的内存空间。

无须借助垃圾回收器来处理不再被引用的对象。

标量替换

标量:仅能存储一个值的变量,比如 Java 代码中的局部变量
聚合量:可能同时存储多个值,其中一个典型的例子便是 Java 对象

标量替换这项优化技术,可以看成将原本对对象的字段的访问,替换为一个个局部变量的访问。

对上述代码标量替换后,由于Itr对象没有被实际分配,因此和栈上分配一样,它同样可以减轻垃圾回收的压力。


public void forEach(ArrayList<Object> list, Consumer<Object> f) {
  // Itr iter = new Itr; // 经过标量替换后该分配无意义,可以被优化掉
  int cursor = 0;     // 标量替换
  int lastRet = -1;   // 标量替换
  int expectedModCount = list.modCount; // 标量替换
  while (cursor < list.size) {
    if (list.modCount != expectedModCount)
      throw new ConcurrentModificationException();
    int i = cursor;
    if (i >= list.size)
      throw new NoSuchElementException();
    Object[] elementData = list.elementData;
    if (i >= elementData.length)
      throw new ConcurrentModificationException();
    cursor = i + 1;
    lastRet = i;
    Object obj = elementData[i];
    f.accept(obj);
  }
}

部分逃逸分析

public static void bar(boolean cond) {
  Object foo = new Object();
  if (cond) {
    foo.hashCode();
  }
}
// 经过部分逃逸分析,优化为:
public static void bar(boolean cond) {
  if (cond) {
    Object foo = new Object();
    foo.hashCode();
  }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值