逃逸分析:解锁性能的神秘钥匙!

这篇具有很好参考价值的文章主要介绍了逃逸分析:解锁性能的神秘钥匙!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

优质博文:IT-BLOG-CN

面试管坑位:在Java中新创建的对象一定是在堆上分配内存吗?如果你的答案是“是的”那就需要看看这个文章了。

一、简介

逃逸分析Escape Analysis:是一个很重要的JIT优化技术,用于判断对象是否会在方法外部被访问到,也就是逃出方法的作用域。逃逸分析是JIT编译器的一个步骤,通过JIT我们能够确定哪些对象可以被限制在方法内部使用,不会逃逸到外部,然后可以对它们进行优化,比如把它们分配在栈上而不是堆上,或者进行标量替换,把一个对象拆散成多个基本类型来存储。是一种可以有效减少Java程序中同步负载内存堆分配和垃圾回收压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新对象的引用的使用范围,而决定是否要将这个对象分配到堆上

逃逸分析主要针对局部变量,判断堆上分配的对象是否逃逸出方法的作用域。它同编译器优化原理的指针分析和外形分析相关联。当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他方法或者线程所引用,这种现象称作指针(或者引用)的逃逸Escape。通俗点讲,如果一个对象的指针被多个方法或者线程引用时,那么我们就称这个对象的指针发生了逃逸。合理地设计代码结构和数据的使用方式能够更好地利用逃逸分析来优化程序的性能。我们还可以通过逃逸分析减少堆上分配对象的开销,提高内存利用率。

逃逸分析不是直接的优化手段,而是代码分析手段。

二、逃逸分析的好处

【1】栈上分配,可以降低垃圾收集器运行的频率。
【2】同步消除,如果发现某个对象只能从一个线程可访问,那么在这个对象上的操作可以不需要同步。
【3】标量替换,把对象分解成一个个基本类型,并且内存分配不再是分配在堆上,而是分配在栈上。这样的好处有:减少内存使用,因为不用生成对象头。程序内存回收效率高,并且GC频率也会减少。因此对于临时对象或短期使用的对象,尽量使用局部变量来存储,以减少对象逃逸的可能性。对于复杂的数据结构,尽量使用基本类型、数组或集合类,以减少对象的分配和逃逸。
【4】使用final关键字来限制对象的可变性,这样JIT编译器更容易进行逃逸分析和优化。

三、why

栈上分配Stack Allocations:在Java虚拟机中,Java堆上分配创建对象的内存空间几乎是Java程序员都知道的常识,Java堆中的对象对于各个线程都是共享和可见的,只要持有这个对象的引用,就可以访问到堆中存储的对象数据。虚拟机的垃圾收集子系统会回收堆中不再使用的对象,但回收动作无论是标记筛选出可回收对象,还是回收和整理内存,都需要耗费大量资源。如果确定一个对象不会逃逸出线程之外,那让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,垃圾收集子系统的压力将会下降很多。栈上分配可以支持方法逃逸,但不能支持线程逃逸。

标量替换Scalar Replacement 若一个数据已经无法再分解成更小的数据来表示了,Java虚拟机中的原始数据类型都不能再进一步分解,那么这些数据就可以被称为标量。相对的,如果一个数据可以继续分解,那它就被称为聚合量AggregateJava中的对象就是典型的聚合量。如果把一个Java对象拆散,根据程序访问的情况,将其用到的成员变量恢复为原始类型来访问,这个过程就称为标量替换。假如逃逸分析能够证明一个对象不会被方法外部访问,并且这个对象可以被拆散,那么程序真正执行的时候将可能不去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来代替。将对象拆分后,除了可以让对象的成员变量在栈上(栈上存储的数据,很大机会被虚拟机分配至物理机器的高速寄存器中存储)分配和读写之外,还可以为后续进一步的优化手段创建条件。标量替换可以视作栈上分配的一种特例,实现更简单(不用考虑整个对象完整结构的分配),但对逃逸程度的要求更高,它不允许对象逃逸出方法范围内。

同步消除Synchronization Elimination 线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那么这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以安全地消除掉。需要注意的是:这种情况针对的是synchronized锁,而对于Lock锁,则JVM并不能消除。

代码说明: 但是在实际的应用程序中,尤其是大型程序中反而发现实施逃逸分析可能出现效果不稳定的情况,或分析过程耗时但却无认开启的选项。如果有需要用户可以使用参数-XX:+DoEscapeAnalysis来手动开启逃逸分析法有效判别出非逃逸对象而导致性能下降。

public class EscapeTest {
    /**
     * JIT编译时会对代码进行逃逸分析
     * 并不是所有对象存放在堆区,有的一部分存在线程栈空间
     * Person没有逃逸
     */
    private static String alloc() {
        Person person = new Person();
        return person.toString();
    }

    /**
     * 同步省略(锁消除)JIT编译阶段优化,JIT经过逃逸分析之后发现无线程安全问题,就会做锁消除
     */
    public void append(String str1, String str2) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(str1).append(str2);
    }

    /**
     * 标量替换
     */
    private static void test2() {
        Point point = new Point(1,2);
        System.out.println("point.x="+point.getX()+"; point.y="+point.getY());
        // 编译后的伪代码,也就是常说的内联后的样子
        // int x=1;
        // int y=2;
        // System.out.println("point.x="+x+"; point.y="+y);
    }
}

四、结论

关于逃逸分析的研究论文早在1999年就已经发表,但直到JDK 6HotSpot才开始支持初步的逃逸分析,而且到现在这项优化技术尚未足够成熟,仍有很大的改进余地。不成熟的原因主要是逃逸分析的计算成本非常高,甚至不能保证逃逸分析带来的性能收益会高于它的消耗。如果要百分之百准确地判断一个对象是否会逃逸,需要进行一系列复杂的数据流敏感的过程间分析,才能确定程序各个分支执行时对此对象的影响。前面介绍即时编译、提前编译优劣势时提到了过程间分析这种大压力的分析算法正是即时编译的弱项。可以试想一下,如果逃逸分析完毕后发现几乎找不到几个不逃逸的对象,那这些运行期耗用的时间就白白浪费了,所以目前虚拟机只能采用不那么准确,但时间压力相对较小的算法来完成分析。这个在JIT优化实战中有说明。

jdk7开始默认开启逃逸分析。在Java代码运行时,可以通过JVM参数指 定是否开启逃逸分析:

XX:+DoEscapeAnalysis //表示开启逃逸分析 (jdk1.8默认开启)XX:DoEscapeAnalysis //表示关闭逃逸分析。XX:+EliminateAllocations //开启标量替换(默认打开)XX:+EliminateLocks //开启锁消除(jdk1.8默认开启)

开启逃逸与关闭逃逸的区别:
【1】关闭逃逸:-XX:-DoEscapeAnalysis -XX:+PrintGC

long start = System.currentTimeMillis();
for(int i=0;i<5000000;i++){
    newObject();
}
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-start)+"毫秒");
Thread.sleep(100000);

结果:41毫秒,一次GC并且有一百多万的垃圾回收。

[GC (Allocation Failure)  65536K->880K(251392K), 0.0013300 secs]
耗时41毫秒

num  #instances    #bytes       class name
1:   1088834       17868374     java.lang.Object

【2】开启逃逸:-XX:+DoEscapeAnalysis -XX:+PrintGC 只有4毫秒,没有GC,提高了快10倍效率,并且堆中只有十几万。逃逸了

耗时4毫秒

num  #instances    #bytes       class name
1:   14534         2734633     java.lang.Object

可以发现一个逃逸和没逃逸的问题,只要是对象有被方法外部或者全局引用到那肯定会存在逃逸。当对象没有发生逃逸的时候,虚拟机会对其进行优化。文章来源地址https://www.toymoban.com/news/detail-742288.html

到了这里,关于逃逸分析:解锁性能的神秘钥匙!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java对象逃逸及逃逸分析

    文章目录 前言 一、对象逃逸是什么? 1.1 概念 1.2 代码分析 二、逃逸分析(一种分析算法) 1.什么是逃逸分析 2.代码优化实践 2.2 同步锁消除 2.3 标量替换分析 总结 随着 JIT 编译器的发展与逃逸分析技术逐渐成熟, 栈上分配、标量替换优化 技术将会导致一些微妙的变化,所有的

    2024年02月05日
    浏览(24)
  • BUUCTF Misc 隐藏的钥匙 & 另外一个世界 & FLAG & 神秘龙卷风

    目录   隐藏的钥匙  另外一个世界 FLAG 神秘龙卷风   下载文件 使用010 editor工具查看 查找flag 将内容复制到base64在线 得到flag               flag{377cbadda1eca2f2f73d36277781f00a}  下载文件 使用010 eitor查看 看到了一串二进制,进行二进制转换字符串  得到flag          flag{koekj3

    2024年02月07日
    浏览(36)
  • 小研究 - Java虚拟机性能及关键技术分析

    利用specJVM98和Java Grande Forum Benchmark suite Benchmark集合对SJVM、IntelORP,Kaffe3种Java虚拟机进行系统测试。在对测试结果进行系统分析的基础上,比较了不同JVM实现对性能的影响和JVM中关键模块对JVM性能的影响,并提出了提高JVM性能的一些展望。 目录 1  Java虚拟机的关键技术 1.1  字

    2024年02月11日
    浏览(23)
  • 小研究 - Java虚拟机垃圾收集器的性能分析与调节

    垃圾收集器是Java虚拟机(JVM)的核心组成部分之一,对Java虚拟机的性能有非常重要的影响。本文将介绍GC的工作原理以及对象回收算法,重点介绍JVM的分段回收技术;剖析JVM自带的GC性能分析工具;阐述如何通过命令行参数调节GC的运行,提

    2024年02月11日
    浏览(25)
  • 解锁Spring AOP的神秘面纱

    Spring AOP作为Spring框架的核心模块,为我们提供了一种优雅的方式来处理横切关注点。本篇博客将从组成、实现和实现原理三个方面深入剖析Spring AOP,并结合具体的例子进行说明。 切面(Aspect):切面是横切关注点的具体实现,它定义了在何处、何时执行横切逻辑。我们可以

    2024年02月12日
    浏览(27)
  • 解锁互联网安全的新钥匙:JWT(JSON Web Token)

    目录 前言 一、JWT简介 1. 什么是JWT? ​编辑 2. JWT的工作原理 3.JWT如何工作的 4. JWT的优势 5. 在实际应用中使用JWT 6.传统Session和JWT认证的区别 6.1.session认证方式 6.2.JWT认证方式 7.基于Token的身份认证 与 基于服务器的身份认证  二、JWT的结构 (1) Header (2) Payload (3) Signature  三、

    2024年02月08日
    浏览(33)
  • 【jvm系列-13】jvm性能调优篇---参数设置以及日志分析

    JVM系列整体栏目 内容 链接地址 【一】初识虚拟机与java虚拟机 https://blog.csdn.net/zhenghuishengq/article/details/129544460 【二】jvm的类加载子系统以及jclasslib的基本使用 https://blog.csdn.net/zhenghuishengq/article/details/129610963 【三】运行时私有区域之虚拟机栈、程序计数器、本地方法栈 https

    2024年02月06日
    浏览(44)
  • 小研究 - JVM 逃逸技术与 JRE 漏洞挖掘研究(一)

    Java语言是最为流行的面向对象编程语言之一, Java运行时环境(JRE)拥有着非常大的用户群,其安全问题十分重要。近年来,由JRE漏洞引发的JVM逃逸攻击事件不断增多,对个人计算机安全造成了极大的威胁。研究JRE安全机制、JRE漏洞及其挖掘、JVM逃逸攻防技术逐渐成为软件安

    2024年02月11日
    浏览(27)
  • JVM:性能监控工具分析和线上问题排查实践

    在日常开发过程中,多少都会碰到一些jvm相关的问题,比如: 内存溢出、内存泄漏、cpu利用率飙升到100%、线程死锁、应用异常宕机 等。 在这个日益内卷的环境,如何运用好工具分析jvm问题,成为每个java攻城狮必备的技能。所以白梦特意整理了 jdk自带分析工具的使用 ,以及

    2024年01月19日
    浏览(33)
  • JVM(Java虚拟机)

    目录 1.JVM 简介 2. JVM 运行时数据区 2.1程序计数器 2.栈 3.堆 4.方法区 3.类加载 1.loading 2.linking 1.验证 2.准备 3.解析 3.Initializing 4.双亲委派模型 5.JVM垃圾回收机制 1.劣势 2.回收什么 3.垃圾回收具体怎么回收 1.找垃圾 方法: 问题: 2.释放垃圾 JVM 是 Java Virtual Machine 的简称,意为 Java虚

    2024年02月01日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包