• JVM笔记-逃逸分析


    参考:

    http://www.iteye.com/topic/473355
    http://blog.sina.com.cn/s/blog_4b6047bc01000avq.html

    什么是逃逸分析(Escape Analysis)?

    在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析。它跟静态代码分析技术中的指针分析和外形分析类似。
    通俗一点讲,当一个对象的指针被多个方法线程引用时,我们称这个指针发生了逃逸。
    而用来分析这种逃逸现象的方法,就称之为逃逸分析。
    举个例子:

    class A {
      public static B b;
      public void globalVariablePointerEscape() { // 给全局变量赋值,发生逃逸
        b = new B();
      }
     
      public B methodPointerEscape() { // 方法返回值,发生逃逸
        return new B();
      }
     
      public void instancePassPointerEscape() {
        methodPointerEscape().printClassName(this); // 实例引用传递,发生逃逸
      }
    }
     
    class B {
      public void printClassName(A a) {
        System.out.println(a.class.getName());
      }
    }

    在这个例子中,一共举了3种常见的指针逃逸场景。分别是 全局变量赋值,方法返回值,实例引用传递。

    逃逸分析优化JVM原理

    我们知道java对象是在里分配的,在调用中,只保存了对象的指针

    当对象不再使用后,需要依靠GC来遍历引用树并回收内存,如果对象数量较多,将给GC带来较大压力,也间接影响了应用的性能。减少临时对象在堆内分配的数量,无疑是最有效的优化方法。

    怎么减少临时对象在堆内的分配数量呢?不可能不实例化对象吧!

    场景介绍

    其实,在java应用里普遍存在一种场景。一般是在方法体内,声明了一个局部变量,且该变量在方法执行生命周期内未发生逃逸(在方法体内,未将引用暴露给外面)。

    按照JVM内存分配机制,首先会在堆里创建变量类的实例,然后将返回的对象指针压入调用栈,继续执行。

    这是优化前,JVM的处理方式。

    逃逸分析优化 - 栈上分配

    优化原理:分析找到未逃逸的变量,将变量类的实例化内存直接在栈里分配(无需进入堆),分配完成后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收

    这是优化后的处理方式,对比可以看出,主要区别在栈空间直接作为临时对象的存储介质。从而减少了临时对象在堆内的分配数量。

    例子

    public void my_method(){
        V v=new V();
        //use v
        ......
        v=null;
    }
        在这个方法中创建的局部对象被赋给了v,但是没有返回,没有赋给全局变量等等操作,因此这个对象是没有逃逸的,是可以在运行时栈进行分配和销毁的对象。没有发生逃逸的对象由于生命周期都在一个方法体内,因此它们是可以在运行时栈上分配并销毁。

    逃逸分析的原理很简单,但JVM在应用过程中,还是有诸多考虑。

    比如,逃逸分析不能在静态编译时进行,必须在JIT里完成。原因是,与java的动态性有冲突。因为你可以在运行时,通过动态代理改变一个类的行为,此时,逃逸分析是无法得知类已经变化了。

    逃逸分析另一个重要的优化 - 同步消除

    如果你定义的类的方法上有同步锁,但在运行时,却只有一个线程在访问,此时逃逸分析后的机器码,会去掉同步锁运行。

    ======================================================

    性能测试

    来自 http://blog.uncommons.org/ 性能测试结果。

    测试场景1:

    生成几百万个随机数,然后做一些少量运算。

    VM 参数: -server
    95 秒
    VM 参数: -server -XX:+DoEscapeAnalysis
    73 秒

    性能提高: 23%

    测试场景2:

    非负矩阵分解算法。

    VM 参数: -server
    22.6 秒
    VM 参数: -server -XX:+DoEscapeAnalysis
    20.8 秒

    性能提升: 8%

    JVM中启用逃逸分析 DoEscapeAnalysis

    安装jdk1.6.0_14,运行java时传递jvm参数  -XX:+DoEscapeAnalysis

    逃逸分析还能用于以下优化场景,但在JVM中未知使用。

    1,标量替换(Scalar Replacement)

    2,减小竞争检测范围

    3,基于区域的内存分配

  • 相关阅读:
    针对Ext js的分页存储过程适用于sqlserver2008
    30分钟LINQ教程
    windows server 2003 sp2安装VS2010之后需要打的几个布丁
    【翻译】Prism4:初始化Prism应用程序(上)
    ASP.NET WebAPI 路由规则与POST数据
    基于.net开发chrome核心浏览器【二】
    六种SQL Server删除重复行的方法
    Web在线操作Office文件 (转)
    ASP.NET 中如何对生成的 HTML 内容流进行控制?
    使用键值表实现通用流水号(转)
  • 原文地址:https://www.cnblogs.com/gnivor/p/6028001.html
Copyright © 2020-2023  润新知