zoukankan      html  css  js  c++  java
  • 对没有发生指针逃逸局部对象使用栈上分配和销毁方式,来提高效率

    一、什么是指针逃逸

    逃逸分析(Escape Analysis),在计算机编译器优化原理中,逃逸分析是指分析指针动态范围的方法,它同编译器优化原理的指针分析和外形分析相关联。计算机软件方面,逃逸分析指的是计算机语言编译器语言优化管理中,分析指针动态范围的方法。通俗讲,如果一个对象的指针被多个线程或者方法引用,那么称这个指针发生了逃逸。java语言也有逃逸的情况存在,实例代码如下。

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

    上述代码,举了3个常见的指针逃逸的场景:全局变量赋值、方法返回值、实例引用传递。

    二、逃逸分析对java编译器有什么好处呢?

    我们知道java对象是在堆中进行分配的,因此java对象的创建和回收对系统的开销是很大的。java语言被诟病的一个地方,就是认为java性能慢的一个原因就是java不支持运行时栈上分配对象,缺少像c#里面的值对象或者C++里面的struct结构。栈里面只保存了对象的指针,当对象不再被使用后,需要依靠GC来遍历引用树并回收内存。如果对象数量较多,讲给GC带来较大的压力,也间接影响了应用的性能。减少临时对象在堆内存分配的数量,将是一种有效的优化方法。

    在java应用里普遍存在一种场景,一般是在方法体内,声明了一局部变量,且该变量在方法执行声明周期内未发生逃逸,因为在方法体内未将引用暴露给外面。按照jvm内存分配机制,首先会在堆里面创建类变量类的实例,然后将返回的对象指针压入调用栈在,继续执行,这是优化前的方式。

    我们可以采用 逃逸分析原理对jvm进行优化, 对于没有发生逃逸的对象由于生命周期都在一个方法体内,因此他们可以在运行时栈上进行分配并销毁,提高java的运行效率。

    栈上分配:采用逃逸分析技术原理对JVM进行优化,即针对栈的重新分配方式。首先我们先要分析并且找到未逃逸的变量,将变量类的实例化内存直接在栈上进行分配(无需进入堆),分配完成后,继续再调用栈内执行,最后线程结束,栈空间被回收局部变量对象也被回收。通过这种优化方式,与优化前的方案主要区别在栈空间直接作为临时对象的存储介质,从而减少了对象在堆内存的分配数量。

    package com.lwh.jvm;
    /**
     * 未发生指针逃逸的局部变量可以使用栈上分配对象方式来提高效率。
     * 对于没有发生逃逸的对象由于生命周期都在一个方法体内,因此他们可以在运行时栈上进行分配并销毁,提高java的运行效率
     * 栈上分配:采用逃逸分析技术原理对JVM进行优化,即针对栈的重新分配方式。首先我们先要分析并且找到未逃逸的变量,
     * 将变量类的实例化内存直接在栈上进行分配(无需进入堆),分配完成后,继续再调用栈内执行,最后线程结束,栈空间被回收
     * 局部变量对象也被回收。通过这种优化方式,与优化前的方案主要区别在栈空间直接作为临时对象的存储介质,从而减少了对象在堆内存的分配数量。
     * @author luwenhu
     *
     */
    public class StackAllocateObject {
        public void my_method(){
            B b=new B();
            //user b
            //....
            b=null;
        }
    }

    (3)逃逸分析还有其他两个优化应用

    a、同步消除:我们知道线程同步的代价是相当高的。同步的后果是降低并发性和性能。逃逸分析可以判断出某个对象是否始终会被一个线程访问。如果只被一个线程访问,那么对该对象的同步操作就可以转化成没有同步保护的操作,提高并发程序的性能。

    b、矢量替换:逃逸分析方法如果发现对象的内存存储结构不需要连续进行的话,就可以将对象的部分甚至全部都保存早CPU寄存器内,这样就大大提高访问速度了。

  • 相关阅读:
    HDU 1166 敌兵布阵 我的第一棵树,线段树,树状数组。
    HDU 2544 最短路 第一个图论问题。
    位运算简介及实用技巧(三):进阶篇(2)
    用匈牙利算法求二分图的最大匹配
    求两个字符串的最长公共子序列的长度(动态规划)
    搜索之深度优先【迷宫搜索】(判断是否n步恰好可以到达某点)
    HDU 2955 Robberies
    STL简介
    HDU 1257 最少拦截系统
    HDU 2034 人见人爱AB
  • 原文地址:https://www.cnblogs.com/wenhulu/p/7519652.html
Copyright © 2011-2022 走看看