作者:栈长  公众号: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 逃逸分析的更多相关文章

  1. 面试问我 Java 逃逸分析,瞬间被秒杀了。。

    记得几年前有一次栈长去面试,问到了这么一个问题: Java中的对象都是在堆中分配吗?说明为什么! 当时我被问得一脸蒙逼,瞬间被秒杀得体无完肤,当时我压根就不知道他在考什么知识点,难道对象不是在堆中分配 ...

  2. Java逃逸分析

    Java逃逸分析 记录下看到的别人的博客内容,以后深入了解再详细写篇,加深下基础概念和印象! 一般来说,Java对象的创建,通常是在堆空间中分配内存,但是如果大量的临时对象也在堆空间创建的话,会导致性 ...

  3. 深入理解Java中的逃逸分析

    在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. ...

  4. Java之JVM逃逸分析

    引言: 逃逸分析(Escape Analysis)是众多JVM技术中的一个使用不多的技术点,本文将通过一个实例来分析其使用场景. 概念 逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配 ...

  5. java中的逃逸分析

    逃逸分析 public static StringBuffer craeteStringBuffer(String s1, String s2) { StringBuffer sb = new Str ...

  6. 面试官:Java中对象都存放在堆中吗?你知道逃逸分析?

    面试官:Java虚拟机的内存分为哪几个区域? 我(微笑着):程序计数器.虚拟机栈.本地方法栈.堆.方法区 面试官:对象一般存放在哪个区域? 我:堆. 面试官:对象都存放在堆中吗? 我:是的. 面试官: ...

  7. java虚拟机的逃逸分析

    逃逸分析作为其他优化手段提供依据的分析技术,其基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸.甚至还有可能被外部线程 ...

  8. JVM中启用逃逸分析

    -XX:+DoEscapeAnalysis 逃逸分析优化JVM原理我们知道java对象是在堆里分配的,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量 ...

  9. JVM笔记-逃逸分析

    参考: http://www.iteye.com/topic/473355http://blog.sina.com.cn/s/blog_4b6047bc01000avq.html 什么是逃逸分析(Es ...

随机推荐

  1. 洛谷 P4408 [NOI2003]逃学的小孩

    题目传送门 题目描述 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:“喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?”一听说要考试,Chris的父母就心急如焚, ...

  2. Milk Pumping

    今天第一次正式打个人定位赛,还是太菜,这题连枚举加最短路都没想到,显然菜是原罪. 题面: : 题解:其实方法很多,千万别浪到网络流用dinic求最大网络流求的最小费用,这题不一样.最大流/最小费用 不 ...

  3. 数据可视化之分析篇(五)如何使用Power BI计算新客户数量?

    https://zhuanlan.zhihu.com/p/65119988 每个企业的经营活动都是围绕着客户而开展的,在服务好老客户的同时,不断开拓新客户是每个企业的经营目标之一. 开拓新客户必然要付 ...

  4. hihoCoder 1049 后序遍历 最详细的解题报告

    题目来源:后序遍历 解题思路:开始时我只知道先通过先序.中序求出二叉树,然后再后序遍历二叉树,这当然也是一种解题思路,但是会做一些无用功,比如:计算二叉树.其实,可以直接通过先序序列和中序序列直接求出 ...

  5. 微信小程序接口封装、原生接口封装、request、promise封装

    相信大家在做微信小程序的时候会有很多地方需要调用接口,就和pc以及手机端一样,多个页面多次调用会有很多状态,那为了节省大家的开发时间就会需要给请求的接口做一些简单封装,便于开发,在这里我用了两个js, ...

  6. someone you loved 歌词翻译

    I'm going under and this time I fear there's no one to save me 我要放弃了,这一次我怕没有人可以拯救我. This all or noth ...

  7. 【软件安装】CentOS7安装MariaDb(mysql_替代品安装)

    1.背景 Maria Db是流行的跨平台MySQL数据库管理系统的分支,被认为是MySQL 的完全替代品.Maria Db是由Sun在Sun Micro systems合并期间被Oracle收购后,于 ...

  8. Apache 阿帕奇 配置运行环境

    阿帕奇 Apache 是一个很常用的服务器环境. 安装阿帕奇后,需要对配置文件进行修改,才能使用. https.conf是阿帕奇的配置文件,地址在 阿帕奇的安装目录\conf\httpd.conf 默 ...

  9. 地图热点 jquery.image-maps.js 的使用

    在我悠闲了几天之后,我们后端给了我个任务,地图热点问题.简单来说,就是后台划出热点区域,设置链接,前端拿到数据渲染页面,显示热点区域.我主要使用了jquery.image-maps.js,并且添加了一 ...

  10. 手把手教你基于C#开发WinCC语音报警插件「附源代码」

    写在前面 众所周知,WinCC本身是可以利用C脚本或者VBS脚本来做语音报警,但是这种方式的本质是调用已存在的音频文件,想要实现实时播报报警信息是不行的,灵活性还不够,本文主要介绍基于C#/.NET开 ...