欲渡黄河冰塞川,将登太行雪满山,困难一直都有,阻力也一直都存在,可做事情的初心是什么,就是渡黄河和登太行呀,而且若非冰塞川,和雪满山,或许我们做的事情也就没那么有意义了。
下面讲讲JVM逃逸分析
啥是逃逸,看下官方说法:
如果一个子程序分配一个对象并返回一个该对象的指针,该对象可能在程序中被访问到的地方无法确定——这样指针就成功“逃逸”了。如果指针存储在全局变量或者其它数据结构中,因为全局变量是可以在当前子程序之外访问的,此时指针也发生了逃逸
jvm判断逃逸:
JVM判断新创建的对象是否逃逸的依据有:一、对象被赋值给堆中对象的字段和类的静态变量。二、对象被传进了不确定的代码中去运行。如果满足了以上情况的任意一种,那这个对象JVM就会判定为逃逸。
说下自己的理解,java编译文件通过两种形式,静态的和运行时的,静态的就是还没运行呢,点击下编译,java就会通过jdk把java文件编译成class字节码文件,而运行时的编译呢,就是通过jit来编译的,而逃逸分析就是针对jit来进行的,jit编译的过程中,jvm需要掌握程序中所有对象的动向,在哪里使用,从而进行GC处理等操作。
逃逸了,就是jvm不清楚这个对象在哪里引用了,因为对象都存储在堆中,我们知道gc是通过找引用来判断对象是否被用,这下找不到了,懵逼了,从而导致oom等问题
这下也就解释了逃逸分析的重要性,看一段代码
public class EscapeTest {
public static Object globalVariableObject;
public Object instanceObject;
public void globalVariableEscape(){
globalVariableObject = new Object(); //静态变量,外部线程可见,发生逃逸 }
public void instanceObjectEscape(){
instanceObject = new Object(); //赋值给堆中实例字段,外部线程可见,发生逃逸 }
public Object returnObjectEscape(){
return new Object(); //返回实例,外部线程可见,发生逃逸 }
public void noEscape(){
synchronized (new Object()){
//仅创建线程可见,对象无逃逸 }
Object noEscape = new Object(); //仅创建线程可见,对象无逃逸 }}
在不启用逃逸分析下,那这些就都逃逸了。
那这么多逃逸,那不gg了吗?也不用担新,jvm是默认开启逃逸分析的
开始逃逸分析
-server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m
关闭逃逸分析
-server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m
那他能干啥呢
1 能够将对象放到栈里面
方法运行的时候把对象放到栈里面,方法运行完,弹出栈,这样就ok了,而且还减少了GC,而且还打破了固有思想的所有对象都分配在堆中。
2 同步锁的优化
如果一个持有同步锁的方法只被一个线程调用那么jit就会把这个锁优化掉
优化前
public synchronized void invoke(){
Object obj = new Object();
}
优化后
publicvoid invoke(){
Object obj = new Object();
}
这段代码也解决了一个疑惑,一个class文件是固定的,jit编译和静态编译应该是一样的,为什么逃逸分析要针对jit,这段代码就是很好的解答
3 分析对象和变量替换
这个的解释就是把对象编程基本类型,然后把他分配上堆上,这个其实也是一种栈上分配