逃逸分析(Escape Analysis)与栈上分配

8 篇文章 0 订阅

逃逸分析

了解JVM内存模型的大都知道Java的对象、数组都是在堆上分配的,实际上JVM还有更高级非分配技术。逃逸分析(Escape Analysis)就是其中之一。

逃逸分析是目前Java虚拟机中比较前言的优化技术,他与类型继承关系分析一样,并不是直接优化代码的手段,而是为前天优化手段提供依据的分析技术。
逃逸分析的基本行为就是分析动向的动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如,作为调用参数传递到其他方法中。成为方法逃逸。甚至还有可能被外部线程访问到,例如赋值给类变量或者可以在其他线程中访问的实例变量,成为现场逃逸。

public class EscapeTest {
    public static Object globalObj;

    // 给全局变量赋值,发生逃逸
    public void globalVariableEscape() {  
        globalObj= new Object();
    }

    // 方法返回值,发生逃逸
    public Object methodEscape() {  
        return new Object();
    }

    // 实例引用发生逃逸
    public void instanceEscape() {  
        test(this); 
    }
}

栈上分配

栈上分配主要是指在Java程序的执行过程中,在方法体中声明的变量以及创建的对象,将直接从该线程所使用的栈中分配空间。 一般而言,创建对象都是从堆中来分配的,这里是指在栈上来分配空间给新创建的对象。

如何启用

在JDK 6之后支持对象的栈上分析和逃逸分析,在JDK 7中完全支持栈上分配对象。 其是否打开逃逸分析依赖于以下JVM的设置:

-XX:+DoEscapeAnalysis

实际效果

jvm的参数 -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+PrintGC
public class AllocationOnStack {

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        for (int index = 0; index < 100000000; index++) {
            allocate();
        }
        long end = System.currentTimeMillis();
        System.out.println((end - start)+ " ms");
        Thread.sleep(1000*1000);
    }

    private static void allocate() {
        byte[] bytes = new byte[2];
        bytes[0] = 1;
        bytes[1] = 1;
    }
}
控制台输出
[GC (Allocation Failure)  2048K->1043K(9728K), 0.0011874 secs]
[GC (Allocation Failure)  3091K->1474K(9728K), 0.0010678 secs]
[GC (Allocation Failure)  3522K->1530K(9728K), 0.0008986 secs]
[GC (Allocation Failure)  3578K->1546K(9728K), 0.0007104 secs]
8 ms


C:\Users\Lenovo>jstat -gc 1516
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0  504.0   0.0    2048.0   1482.5    7168.0     1042.3   4864.0 3259.6 512.0  350.1       4    0.004   0      0.000    0.004

当我们使用参数 -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGC
效果

[GC (Allocation Failure)  3850K->1802K(9728K), 0.0002024 secs]
[GC (Allocation Failure)  3850K->1802K(9728K), 0.0001878 secs]
[GC (Allocation Failure)  3850K->1802K(9728K), 0.0001940 secs]


[GC (Allocation Failure)  6572K->4524K(9728K), 0.0002761 secs]
[GC (Allocation Failure)  6572K->4524K(9728K), 0.0002979 secs]
[GC (Allocation Failure)  6572K->4524K(9728K), 0.0002188 secs]
782 ms

C:\Users\Lenovo>jstat -gc 19176
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
512.0  512.0   0.0    0.0    2048.0   1802.0    7168.0     4562.9   4864.0 3781.7 512.0  411.4    1160    0.350   0      0.000    0.350

结论

在测试程序中,逃逸分析往往能获得不错的成绩,但是在实际应用中,尤其是大型程序中反而发现实施逃逸分析可能出现效果不稳定的情况。 如有需要,可以开启该参数,然后对比实际结果。 开始了-XX:+DoExcapeAnalysis后可以添加参数-XX:PrintEscapeAnalysis开查看分析结果。 有了逃逸分析技术支持后,用户可以使用参数-XX:+EliminateAllocations开开启标量替换,使用 -XX:+EliminateLocks开启同步消除,使用-XX:+PrintEliminateAllocations查看标量替换情况。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JVM 逃逸分析Escape Analysis)是一种用于分析 Java 代码中对象的作用域的技术。它可以帮助 JVM 在运行时确定对象的作用域,从而优化代码的性能。 在 Java 中,对象的生命周期是由它的作用域决定的。如果一个对象在方法内部创建并且只在该方法中使用,那么它的作用域就被限制在了该方法内部。这种对象被称为局部对象(Local Object)。如果一个对象在方法内部创建但是在方法外部被引用,那么它的作用域就被扩展到了方法外部。这种对象被称为逃逸对象(Escape Object)。 JVM 逃逸分析就是用来分析对象的作用域的。通过对代码的分析,JVM 可以确定哪些对象是局部对象,哪些对象是逃逸对象。对于局部对象,JVM 可以在栈上分配内存,这样可以避免在堆上分配内存的开销,从而提高代码的性能。对于逃逸对象,JVM 则必须在堆上分配内存。 JVM 逃逸分析对于代码性能的影响非常大。如果一个方法中大量使用逃逸对象,那么 JVM 将不得不频繁地在堆上分配内存,这将影响代码的性能。但是如果一个方法中大量使用局部对象,那么 JVM 可以将这些对象分配栈上,从而避免在堆上分配内存的开销,这将大大提高代码的性能。 总之,JVM 逃逸分析是一种非常重要的技术,它可以帮助 JVM 在运行时优化代码的性能,提高代码的执行效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值