关于JVM的逃逸分析

何谓“逃逸”?

  我们都知道Java中的对象默认是分配到堆上的,垃圾回收机制也会回收堆中不再使用的对象,但在此之前需要筛选可回收的对象,因此会造成,回收对象还有整理内存,都比较耗时间,开销也是非常之大。而此也是Java语言被疯狂吐槽的一地方,就是Java不支持栈上分配对象。而在我们日常开发中,内存,时间都是相当的宝贵,如何优化成为在开发中一个不可或缺的环节。

  逃逸分析(Escape Analysis),是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。 逃逸分析算是目前Java虚拟机中比较前沿的优化技术了,但至于适不适合,需要据实际情况而定了。

  在计算机语言编译器优化原理中,逃逸分析是指分析指针动态范围的方法,它同编译器优化原理的指针分析和外形分析相关联。当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他方法或者线程所引用,这种现象称作指针(或者引用)的逃逸(Escape)。通俗点讲,如果一个对象的指针被多个方法或者线程引用时,那么我们就称这个对象的指针发生了逃逸。

  网上有位博友这么形容逃逸分析,用了一段简单直接的代码,请看:

public StringBuilder escapeDemo1(System a, System b) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(a);
    stringBuilder.append(b);
    return stringBuilder;
}

  StringBuilder是方法的一个内部变量,而此时将它直接返回,这样StringBuilder就有可能被其他地方的方法或变量改变,这样它的作用域就不只是demo1方法了,虽然它是一个局部变量,但其发生了“逃逸事故”。

  那么,我可以改一下代码:

public String escapeDemo2(System a, System b) {

    StringBuilder stringBuilder = new StringBuilder();

    stringBuilder.append(a);

    stringBuilder.append(b);

    return stringBuilder.toString();

}

  如此再没有返回StringBuilder,而是toString(),那么StringBuilder没有从方法中脱离,将不会发生逃逸。

  换种方式理解吧,因为Java本身的限制(对象只能分配到堆中),我可以这么操作了,为了减少临时对象在堆内分配的数量,我会在一个方法体内定义一个局部变量,并且该变量在方法执行过程中未发生逃逸,按照JVM调优机制,首先会在堆内存创建类的实例,然后将此对象的引用压入调用栈,继续执行,这是JVM优化前的方式。然后,我采用逃逸分析对JVM进行优化。即针对栈的重新分配方式,首先找出未逃逸的变量,将该变量直接存到栈里,无需进入堆,分配完成后,继续调用栈内执行,最后线程执行结束,栈空间被回收,局部变量也被回收了。如此操作,是优化前在堆中,优化后在栈中,从而减少了堆中对象的分配和销毁,从而优化性能。

  但是逃逸分析会有时间消耗,所以性能不一定会有提升,并且由于逃逸分析比较耗时,目前的实现都是采用不那么准确但是时间压力相对较小的算法来完成逃逸分析,这就有可能导致效果不稳定,所以,要根据实际情况,酌情处理。

  一项技术的好坏,不是凭嘴说说,适合自己的才是最好的。

  ok,纯属结合项目实际,整理前人文言,权当学习手札。

你有兴趣,推荐你以下好文:

浅谈HotSpot逃逸分析

Java 逃逸分析

https://dzone.com/articles/escape-analysis-java-6-update

原文地址:https://www.cnblogs.com/fuguoliang/p/9749818.html

时间: 2024-10-07 09:42:13

关于JVM的逃逸分析的相关文章

JVM逃逸分析DoEscapeAnalysis

JVM逃逸分析 JVM有栈.堆.方法区.本地栈等组成 栈:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表.操作栈.动态连接.方法出口等信息.每个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程. 堆:当实例化对象时,会把对象分配到堆中,然后把指向该堆的引用压入栈中. 逃逸:当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸,一般情况返回对象.对全局变量的肤质一般都会发生逃逸. 逃逸分析:用来分析这种逃逸现象的方法称为逃逸分析 逃逸分析优化-栈

JVM逃逸分析

JDK1.8默认开启逃逸分析,这是一种代码分析手段,能动态分析对象的作用域,为其它优化手段如栈上分配.标量替换和同步消除等提供依据. 一共可能有两种逃逸行为:方法逃逸和线程逃逸. 方法逃逸:当一个对象在方法中定义之后,作为参数传递到其它方法中: 线程逃逸:如类变量或实例变量,可能被其它线程访问到: 如果确认不存在逃逸行为,则可以对该对象进行如下优化:同步消除.标量替换和栈上分配. 参考:https://www.jianshu.com/p/20bd2e9b1f03 原文地址:https://www

JVM的学习3_____逃逸分析与栈上分配

之前有提到过,为了提高GC的回收效率,对象实例的内存分配不一定必须存在于堆区中,还可采用堆外分配.而最常见的堆外分配就是采用逃逸分析筛选出未发生逃逸的对象,在栈帧中分配内存空间. 逃逸分析:就是分析出对象的作用域.当一个对象在方法体内声明后,该对象的引用被其他外部所引用时该对象就发生了逃逸,反之就会在栈帧中为对象分配内存空间. 根据逃逸分析在栈帧中分配的对象内存,不会使用GC进行垃圾回收.因为栈会随着方法的开始而创建,结束而销毁. 原文地址:https://www.cnblogs.com/xbf

逃逸分析

[分析对象动态作用域] 方法逃逸,线程逃逸. ——栈上分配:对象可以随着方法的结束而自动销毁. ——同步消除 ——标量替换:将对象中使用到的成员变量恢复原始类型来使用. ======================================================================= 在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析.它跟静态代码分析技术中的指针分析和外形分析类似. 通俗一点讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生

十、逃逸分析和栈上分配

Java堆区已经不再是对象实例分配的唯一空间,可以在堆区之外分配内存以提升效率降低频率,逃逸分析即是如此. 什么是逃逸分析? 例如: 一个成员方法的内部实例化了一个对象,如果这个对象被方法外的引用指向了,那么就发生了逃逸现象.JVM在内存分配的时候会分析其是否发生逃逸,如果未发生逃逸的,那么就直接在栈上分配内存空间,其生命周期和线程相同.(也称之为"栈上分配") 原文地址:https://www.cnblogs.com/lay2017/p/8157760.html

深入理解Java中的逃逸分析

在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. 第一段编译就是javac命令. 在第二编译阶段,JVM 通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译.很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢很多.这就是传统的JVM的解释器(Interpreter)的功能.为了解决这种效率问题,引入了 JIT(即时编译)

JVM源码分析之堆外内存完全解读

概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们大家接触最多的,我们在jvm参数里通常设置-Xmx来指定我们的堆的最大值,不过这还不是我们理解的Java堆,-Xmx的值是新生代和老生代的和的最大值,我们在jvm参数里通常还会加一个参数-XX:MaxPermSize来指定持久代的最大值,那么我们认识的Java堆的最大值其实是-Xmx和-XX:MaxPermSize的总和,在分代算法下,新生代,老生代和持久代是连续的虚拟地址,因为它们是一起分配的,那么剩下的都可以认为是堆外内存

JVM 内存问题分析方法记录

1.GC日志分析 除了CMS的日志和其他GC的日志差别较大外,它们都可以抽象成如下格式 [GC [<collector>:<starting occupancy1>-><ending occupancy1>(total size1), <pause time1> secs] <starting occupancy2>-><ending occupancy2>(total size2), <pause time2>

jvm运行时分析

官方手册: http://docs.oracle.com/javase/7/docs/     ----> http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html   java命令的各种选项的说明 参考书籍: <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> 首先说下JVM的内存堆结构,看下图: 主要由 方法区Permanent Generation + 新生代Eden + 新生代幸存区S