Appearance
逃逸分析的目的是为什么?-GPT4.0的回答
逃逸分析的主要目的是识别出那些不会逃逸出方法作用域的对象,从而可以优化这些对象。如果一个对象不会逃逸出方法作用域,那么它可以被分配在栈上,而不是堆上。由于栈的分配和回收速度比堆要快,因此可以提高程序的性能和效率。逃逸分析的主要目的是为了做优化。
or
逃逸分析(Escape Analysis)是一种编译器优化技术,它在编译Java代码时分析对象的作用域和生命周期。其目的是确定一个对象是否可以在方法或线程的本地范围内“逃逸”出去。如果确定对象不会逃逸到方法或线程之外,编译器就可以做一些优化决策,例如:
栈上分配(Stack Allocation):如果逃逸分析确定一个对象不会逃逸到方法之外。那么通过标量替换实现等效的栈上分配效果(HotSpot 未做真正的栈上分配),而不是在堆上分配这个对象。栈上分配带来的好处是减少了垃圾收集器的压力。因为当方法结束时,栈上的内存会自动回收,无需垃圾回收。
同步消除(Synchronization Elision):如果一个对象被确定为只在一个线程中使用。那么对这个对象的同步操作可能是不必要的。编译器可以消除同步块,从而减少线程同步的开销。
标量替换(Scalar Replacement):编译器可能会将一个对象分解为几个独立的字段。如果逃逸分析表明该对象的引用不会被传递到当前方法之外。这样可以进一步优化性能,因为访问单个字段通常比访问完整对象需要更少的内存访问。
总的来说,逃逸分析的目的是提高 Java 程序的运行效率和性能。途径是减少不必要的堆分配、减少同步负担、做其他可能的优化。
满足逃逸分析需要的条件
来自:https://blog.csdn.net/weixin_43846235/article/details/130417028
1、对象只在方法内部创建,不被方法外部引用。 这个条件意味着:对象只在方法内部使用,并且不会被返回或者传递给其他方法。这样的对象不会逃逸出方法的作用域,可以被分配在栈上,而不是堆上。从而提高程序的性能和效率。
2、对象不会被多线程共享,也不会被外部线程访问。 如果对象不被多个线程共享、不被其他线程访问,它就不会逃逸出当前线程的作用域。这样的对象也可以被分配在栈上,而不是堆上。
3、对象不会被反射机制调用。 如果对象不会被反射机制调用,那么它就不会逃逸出当前方法的作用域。因为反射机制可以绕过Java语言的静态检查,从而获取对象的引用并访问。所以如果对象会被反射机制调用,那么它就无法做逃逸分析。
Java满足逃逸分析需要的条件严格,只有满足了所有的条件才能做逃逸分析。但是如果能够做逃逸分析,就可以优化程序,提高程序的性能和效率。
逃逸分析如何优化Java程序的性能和效率
来自:https://blog.csdn.net/weixin_43846235/article/details/130417028
1、锁消除 (如果局部变量加了锁,则会直接消除锁)
2、栈上分配(判断程序中的对象是否存在逃逸情况。如果不存在,则通过标量替换实现等效的栈上分配效果(HotSpot 未做真正的栈上分配),从而避免在堆上做内存分配和回收的开销)
3、标量替换 1)标量:不可再分,基本数据类型 2)聚合量:可在分,引用类型 3)对不可再分的直接填充
java
int x=1,y=2;
System.out.println(x);
System.out.println(y);
替换
System.out.println(1);
System.out.println(2);使用JVM参数来启用逃逸分析
从Java 6开始,逃逸分析就默认是启用的。但是,有些情况下,JVM会禁用逃逸分析,例如:
- 在使用了一些特定的JVM参数时,例如-XX:+PrintCompilation、-XX:+PrintInlining等。
- 在使用了一些特定的JavaAPI时,例如System.identityHashCode()、java.lang.ref.WeakReference等。
- 在使用了一些特定的编译器插件或者工具时。
- 在使用了一些特定的代码模式或者设计模式时,例如单例模式等。
在这些情况下,逃逸分析可能会被禁用,从而无法优化程序。如果需要确保逃逸分析一直处于启用状态,可以使用JVM参数-XX:+DoEscapeAnalysis来显式启用逃逸分析。
这个示例代码创建了100000000个Point对象,并且获取每个对象的x属性。由于这些对象的创建和使用都在方法内部。并且不会被方法外部引用、不会被多线程共享、不会被反射机制调用。所以它们都可以被分配在栈上,而不是堆上。这样就可以避免在堆上做内存分配和回收的开销,提高程序的性能和效率。
java
java -XX:+DoEscapeAnalysis EscapeAnalysisDemo
public class EscapeAnalysisDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
Point p = new Point(i, i);
p.getX();
}
long end = System.currentTimeMillis();
System.out.println("Time: " + (end - start) + "ms");
}
private static class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
}