[转]Java 逃逸分析
作者:栈长 公众号:Java技术栈
记得几年前有一次栈长去面试,问到了这么一个问题:Java中的对象都是在堆中分配吗?说明为什么!
当时我被问得一脸蒙逼,瞬间被秒杀得体无完肤,当时我压根就不知道他在考什么知识点,难道对象不是在堆中分配吗?最后就没然后了,回去等通知了。。
1. 什么是逃逸分析?
关于 Java 逃逸分析的定义:
逃逸分析(Escape Analysis)简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术。
逃逸分析的 JVM 参数如下:
- 开启逃逸分析:-XX:+DoEscapeAnalysis
- 关闭逃逸分析:-XX:-DoEscapeAnalysis
- 显示分析结果:-XX:+PrintEscapeAnalysis
逃逸分析技术在 Java SE 6u23+ 开始支持,并默认设置为启用状态,可以不用额外加这个参数。
2. 逃逸分析算法
Java Hotspot 编译器实现下面论文中描述的逃逸算法:
[Choi99] Jong-Deok Choi, Manish Gupta, Mauricio Seffano,
Vugranam C. Sreedhar, Sam Midkiff,
"Escape Analysis for Java", Procedings of ACM SIGPLAN
OOPSLA Conference, November 1, 1999
根据 Jong-Deok Choi, Manish Gupta, Mauricio Seffano,Vugranam C. Sreedhar, Sam Midkiff 等大牛在论文《Escape Analysis for Java》中描述的算法进行逃逸分析的。
该算法引入了连通图,用连通图来构建对象和对象引用之间的可达性关系,并在此基础上,提出一种组合数据流分析法。
由于算法是上下文相关和流敏感的,并且模拟了对象任意层次的嵌套关系,所以分析精度较高,只是运行时间和内存消耗相对较大。
3. 对象逃逸状态
我们了解了 Java 中的逃逸分析技术,再来了解下一个对象的逃逸状态。
3.1 全局逃逸(GlobalEscape)
即一个对象的作用范围逃出了当前方法或者当前线程,有以下几种场景:
- 对象是一个静态变量
- 对象是一个已经发生逃逸的对象
- 对象作为当前方法的返回值
3.2 参数逃逸(ArgEscape)
即一个对象被作为方法参数传递或者被参数引用,但在调用过程中不会发生全局逃逸,这个状态是通过被调方法的字节码确定的。
3.3 没有逃逸
即方法中的对象没有发生逃逸。
4. 逃逸分析优化
针对上面第三点,当一个对象没有逃逸时,可以得到以下几个虚拟机的优化。
4.1 锁消除
我们知道线程同步锁是非常牺牲性能的,当编译器确定当前对象只有当前线程使用,那么就会移除该对象的同步锁。
例如,StringBuffer 和 Vector 都是用 synchronized 修饰线程安全的,但大部分情况下,它们都只是在当前线程中用到,这样编译器就会优化移除掉这些锁操作。
锁消除的 JVM 参数如下:
- 开启锁消除:-XX:+EliminateLocks
- 关闭锁消除:-XX:-EliminateLocks
锁消除在 JDK8 中都是默认开启的,并且锁消除都要建立在逃逸分析的基础上。
4.2 标量替换
首先要明白标量和聚合量,基础类型和对象的引用可以理解为标量,它们不能被进一步分解。而能被进一步分解的量就是聚合量,比如:对象。
对象是聚合量,它又可以被进一步分解成标量,将其成员变量分解为分散的变量,这就叫做标量替换。
这样,如果一个对象没有发生逃逸,那压根就不用创建它,只会在栈或者寄存器上创建它用到的成员标量,节省了内存空间,也提升了应用程序性能。
标量替换的 JVM 参数如下:
- 开启标量替换:-XX:+EliminateAllocations
- 关闭标量替换:-XX:-EliminateAllocations
- 显示标量替换详情:-XX:+PrintEliminateAllocations
标量替换同样在 JDK8 中都是默认开启的,并且都要建立在逃逸分析的基础上。
4.3 栈上分配
当对象没有发生逃逸时,该对象就可以通过标量替换分解成成员标量分配在栈内存中,和方法的生命周期一致,随着栈帧出栈时销毁,减少了 GC 压力,提高了应用程序性能。
5. 总结
逃逸分析讲完了,总结了不少时间,我们也应该大概知道逃逸分析是为了优化 JVM 内存和提升程序性能的。
我们知道这点后,在平时开发过程中就要可尽可能的控制变量的作用范围了,变量范围越小越好,让虚拟机尽可能有优化的空间。
简单举一个例子吧,如:
return sb;
可以改为:
return sb.toString();
这是一种优化案例,把 StringBuilder 变量控制在了当前方法之内,没有逃出当前方法作用域。
参考资料:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis
https://blog.csdn.net/rickiyeat/article/details/76802085
https://blog.csdn.net/baichoufei90/article/details/85180478
[转]Java 逃逸分析的更多相关文章
- 面试问我 Java 逃逸分析,瞬间被秒杀了。。
记得几年前有一次栈长去面试,问到了这么一个问题: Java中的对象都是在堆中分配吗?说明为什么! 当时我被问得一脸蒙逼,瞬间被秒杀得体无完肤,当时我压根就不知道他在考什么知识点,难道对象不是在堆中分配 ...
- Java逃逸分析
Java逃逸分析 记录下看到的别人的博客内容,以后深入了解再详细写篇,加深下基础概念和印象! 一般来说,Java对象的创建,通常是在堆空间中分配内存,但是如果大量的临时对象也在堆空间创建的话,会导致性 ...
- 深入理解Java中的逃逸分析
在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. ...
- Java之JVM逃逸分析
引言: 逃逸分析(Escape Analysis)是众多JVM技术中的一个使用不多的技术点,本文将通过一个实例来分析其使用场景. 概念 逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配 ...
- java中的逃逸分析
逃逸分析 public static StringBuffer craeteStringBuffer(String s1, String s2) { StringBuffer sb = new Str ...
- 面试官:Java中对象都存放在堆中吗?你知道逃逸分析?
面试官:Java虚拟机的内存分为哪几个区域? 我(微笑着):程序计数器.虚拟机栈.本地方法栈.堆.方法区 面试官:对象一般存放在哪个区域? 我:堆. 面试官:对象都存放在堆中吗? 我:是的. 面试官: ...
- java虚拟机的逃逸分析
逃逸分析作为其他优化手段提供依据的分析技术,其基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸.甚至还有可能被外部线程 ...
- JVM中启用逃逸分析
-XX:+DoEscapeAnalysis 逃逸分析优化JVM原理我们知道java对象是在堆里分配的,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量 ...
- JVM笔记-逃逸分析
参考: http://www.iteye.com/topic/473355http://blog.sina.com.cn/s/blog_4b6047bc01000avq.html 什么是逃逸分析(Es ...
随机推荐
- Subset POJ - 3977(折半枚举+二分查找)
题目描述 Given a list of N integers with absolute values no larger than 10 15, find a non empty subset o ...
- 洛谷 P2607 [ZJOI2008]骑士 树形DP
题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里, ...
- Oracle 对表的基本CURD操作
Oracle对表的基本Curd操作: 样式表: 接下来对这张(表明:Stud)表进行Curd操作(请看面SQL代码) 增加新的字段列:alter table Stud add(heigh ...
- ELKF-分布式日志收集分析平台搭建 最小化 配置过程 - 查看收集日志(windows10下搭建)
前言 Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的.这三个产品被设计成一个集成解决方案,称为“Elastic Stack” ...
- Scala 基础(六):Scala变量 (三) 标识符
1 标识符概念 1) Scala 对各种变量.方法.函数等命名时使用的字符序列称为标识符 2) 凡是自己可以起名字的地方都叫标识符 2 标识符的命名规则 Scala中的标识符声明,基本和Java是一致 ...
- Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信
Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...
- 精通java并发-wait,notify和notifyAll的总结(含案例)
目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages wait,notify和notifyAll 总结 在调用wait方法时,线程必须要持有被调用对象的锁,当调用wait方 ...
- MySQL 三万字精华总结 + 面试100 问,吊打面试官绰绰有余(收藏系列)
写在之前:不建议那种上来就是各种面试题罗列,然后背书式的去记忆,对技术的提升帮助很小,对正经面试也没什么帮助,有点东西的面试官深挖下就懵逼了. 个人建议把面试题看作是费曼学习法中的回顾.简化的环节,准 ...
- OSCP Learning Notes - Exploit(2)
Compiling an Exploit Exercise: samba exploit 1. Search and download the samba exploit source code fr ...
- 集训 T3-难题
大致题意: 求方程 \(a_1+a_2+...+a_n=m\) 的非负整数解有几个. 基本思路: 深搜,虽然看起来可能会超时,但是对于100%的数据,0<=n,m<32767,结果< ...