面试题:说说逃逸分析和栈上分配

说说逃逸分析和栈上分配

  • 逃逸分析:

    • 它是可以有效减少java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。它能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。

    • 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。

    • 当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。例如作为调用参数传递到其他地方。

    • 什么情况下认为逃逸:

       /*
          对象的作用域仅在当前方法中有效,没有发生逃逸
           */
          public void useEscapeAnalysis(){
              EscapeAnalysis e = new EscapeAnalysis();
          }
      
          public static String createStringBuffer(String s1,String s2){
              StringBuffer sb = new StringBuffer();
              sb.append(s1);
              sb.append(s2);
              return sb.toString();
          }
      
  • 逃逸分析的作用:

    • 栈上分配:将堆分配转化为栈分配。如果一个对象在子程序中被分配,要是指向该对象的指针不会逃逸,对象可能是栈分配的候选。

    • 同步省略:如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以考虑不同步。

      • 线程同步的代价是相当高的,同步的后果是降低并发性和性能。
      • 在动态编译同步块的时候,JIT编译器可以借助逃逸分析来判断同步块所使用的锁对象是否只能被一个线程访问而没有发布到其他线程。如果没有,则可以取消这部分代码的同步,也叫锁消除。
      public void f(){
          Object hollis = new Object();
          synchronized(hollis){
              System.out.println(hollis);
          }
      }
      
      /**
      * 优化成下方的
      */
      public void f(){
          Object hollis = new Object();
              System.out.println(hollis);
      }
      
      
    • 标量替换:有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分可以不存储在内存,而且存在CPU寄存器中。

      • 标量是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量。在JIT阶段,如果经历逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换。
      public static void main(String[] args){
          alloc();
      }
      private static void alloc(){
          Point point = new Point(1,2);
          System.out.println(point.x+point.y);
      }
      class Point{
          private int x;
          private int y;
      }
      
      /**
      *替换成下面这种
      */
      private static void alloc(){
          int x = 1;
          int y = 2;
          System.out.println(x+y);
      }
      
      
    • 可以看到,Point这个聚合量经过逃逸分析后,发现他没有逃逸,就被换成2个聚合量,就可以减少堆内存的占用。因为一旦不需要创建对象,那么就不再需要分配堆内存了。

原文地址:https://www.cnblogs.com/dalianpai/p/14149190.html