Java垃圾回收机制-可达性分析算法解析
前言
Java回收机制是什么?可达性分析算法,可达性分析算法最重要的就是要先知道哪些对象死了,怎么知道对象已经死了呢,就要找到GCRoot对象,然后顺着引用路径一直找下去,如果GCRoot下面没有对象引用链,那么这些对象就可以认为是濒临死亡状态,等着垃圾回收器回收了。那么哪些对象是GCRoot对象,这个是关键,所以先要搞清楚GC Roots对象包含哪些,下面我来给大家通过GC Roots的对象定义,以及代码示例来简单理解一下java中GC是如何判断对象存活的。
一、可达性分析
在java中,作为GC Roots的对象包括
- 方法区:类静态属性的对象
- 方法区:常量的对象
- 虚拟机栈(本地变量表)中的对象
- 本地方法栈JNI(Native)中的对象
public class GCRootsTest {
/**
* 可达性分析算法
*/
Object o =new Object();
static Object GCRoot1 =new Object(); //GC Roots
final static Object GCRoot2 =new Object();//GC Roots
public void haveGCRootMethod() {
//可达
Object object1 = GCRoot1; //=不是赋值,在对象中是引用,传递的是右边对象的地址
Object object2 = object1;
Object object3 = object1;
Object object4 = object3;
}
public void notGCRootMethod(){
//不可达(方法运行完后可回收)
Object object5 = o;//o不是GCRoots
Object object6 = object5;
Object object7 = object5;
}
//本地变量表中引用的对象
public void stack(){
Object ostack =new Object(); //本地变量表的对象
Object object8 = ostack;
//以上object8 在方法没有(运行完)出栈前都是可达的
}
}
参考示意图:
二、结果分析
haveGCRootMethod方法中:
static Object GCRoot1 =new Object(); //GC Roots
final static Object GCRoot2 =new Object();//GC Roots
这两段代码的属性声明,分别是静态和常量,均在方法区中,所以是GC Roots节点,我们找到了GCRoot节点,随后object1、object2、object3、object4依次引用GCRoot1节点,自然形成图中的一条引用链,所以这几个对象都是活着的,不会被垃圾回收器回收。
notGCRootMethod方法中:
首先,要知道类中声明的代码段o不是GCRoot对象
Object o =new Object();
o这个对象在哪呢,它不在GCRoots区域,它在区域外面,我忘记画了o
当notGCRootMethod方法执行过程中,object5、object6、object7均在GCRoot区域中,但是object5引用了非GCRoots区域的o对象,指向o,随着方法运行结束,那么object5、object6、object7将会移出GCRoots区域,这个时候就是你看见图中所在的位置,接着,等着被垃圾回收器回收。
stack方法中:
是本地变量表中引用的对象,在方法没有执行结束之前,object8都是可达的,并且引用ostack对象,存在GCRoots区域中,但是当方法结束以后,就会像上图那样移出GCRoots区域,等着被垃圾回收器回收
三、如何减少OOM概率
- 尽可能少的发生内存泄露
- 尽可能不在循环中申请内存
- 尽可能不在调用次数多的函数申请内存