深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
28017 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

23 | 逃逸分析

郑雨迪 2018-09-12
我们知道,Java 中Iterable对象的 foreach 循环遍历是一个语法糖,Java 编译器会将该语法糖编译为调用Iterable对象的iterator方法,并用所返回的Iterator对象的hasNext以及next方法,来完成遍历。
public void forEach(ArrayList<Object> list, Consumer<Object> f) {
for (Object obj : list) {
f.accept(obj);
}
}
举个例子,上面的 Java 代码将使用 foreach 循环来遍历一个ArrayList对象,其等价的代码如下所示:
public void forEach(ArrayList<Object> list, Consumer<Object> f) {
Iterator<Object> iter = list.iterator();
while (iter.hasNext()) {
Object obj = iter.next();
f.accept(obj);
}
}
这里我也列举了所涉及的ArrayList代码。我们可以看到,ArrayList.iterator方法将创建一个ArrayList$Itr实例。
public class ArrayList ... {
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
...
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
...
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
因此,有同学认为我们应当避免在热点代码中使用 foreach 循环,并且直接使用基于ArrayList.size以及ArrayList.get的循环方式(如下所示),以减少对 Java 堆的压力。
public void forEach(ArrayList<Object> list, Consumer<Object> f) {
for (int i = 0; i < list.size(); i++) {
f.accept(list.get(i));
}
}
实际上,Java 虚拟机中的即时编译器可以将ArrayList.iterator方法中的实例创建操作给优化掉。不过,这需要方法内联以及逃逸分析的协作。
在前面几篇中我们已经深入学习了方法内联,今天我便来介绍一下逃逸分析。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(10)

  • 魏春河
    怎么看出来对象是否放入堆中?不是所有的对象都在堆中吗
    2018-09-12
    13
  • 三木子
    本章介绍逃逸分析的优化作用,那么它有什么不足的地方吗?
    2018-09-12
    2
  • 乘风
    看了此篇后有一些疑惑:
    1.为什么对象存入到堆中就无法追踪其代码位置? 当基于全局的优化确定对象的作用域限定在方法内部,其引用不会发生逃逸,这样的对象虽然存在堆中但其引用作用域固定,不会发生方法逃逸。
    2.逃逸分析的判断依据是对象是否存入到堆中,而后文又讲到HotSpot并没有采用栈上分配,那不是意味着对象是一定分配在堆中吗?
    2019-07-18
    1
    1
  • 9700
    为啥hashCode方法不能内联,22节介绍的native方法,只要被标注了intrinsic,都会被直接内联的啊。
    2019-06-28
    1
    1
  • 倔强
    老师讲的非常好,对jvm的了解更加深入了一些
    2018-09-12
    1
  • Scott
    你好,我翻了一下R大关于escape analysis的一篇知乎回答,里面提到C2可以对不逸出当前线程的锁做消除,这个过程是怎样的?
    2018-09-12
    1
  • 四阿哥
    老师讲的很有帮助,陈列原理,结合事例,有理有据,逻辑清晰,层次鲜明
    2018-09-12
    1
  • 寥若晨星
    同问,“一是看对象是否被存入堆中”,所有对象不是都分配在堆中吗?
    2019-08-26
  • 小橙橙
    第一个示例,加了jvm参数,控制台什么内容都没有打印出来,jdk是1.8
    2018-09-26
  • idiandian
    锁消除的概念很有意思
    2018-09-12
收起评论
10
返回
顶部