引用计数方法
给对象添加一个引用计数器,当有对象引用它时,计数器的值就+1,引用实效时,计数器的值-1。
但是这个方法却解决不了相互引用循环的问题。
比如
class Haha {
public Object instant = null;
public static void test(){
Haha A = new Haha();
Haha B = new Haha();
A.instant = B;
B.instant = A;
A = null;
B = null;
System.gc();
}
}
如果虚拟机采用这种方法,那么这两个对象将不会被回收,但是通过运行,可以发现,GC对这两个对象进行了回收,可以得到一个结论,虚拟机并非采用对象引用的方法。
可达性分析算法
这个算法的基本思想是通过一系列的 “GC Root“ 作为起点,GC Root向下路过的路径是引用链,如果一个对象到GC Root没有引用链,说明这个对象是不可达的,那么虚拟机就判断是可回收对象。
能称为GC Root有下面几种:
1.虚拟机栈中引用的对象。
2.方法区中的静态对象。
3.方法区中的常量对象。
4.native中引用的对象。
但是,GC并不是只能回收那些不可达对象,如果一些对象 “食之无味,弃之可惜”,或者内存不够用,那么GC也会进行回收,取决于引用的类型:
1.强引用
就是我们new出来的对象,存在于堆中,这是垃圾收集器永远不会回收的对象。
大家不要以为new出来的对象永远不能被回收!
在一个函数中,A a = new A(),new出来的对象放在堆中,而a是
强引用,放在栈中,函数结束,a弹出栈, 生命周期结束,堆中new出来的对象也会被回收。
所以说,强引用如果出现在方法中,不用担心 不把它设置 = null 会出现内存泄漏,因为执行方法时,强引用放在栈中,生命周期结束就自然回收了。
2.软引用
将要内存泄漏时,会把软引用指向的对象列到回收范围进行第二次回收。如果还是内存泄漏,那就抛出内存溢出异常。
3.弱引用
可以理解成,无论内存情况如何,下次gc的时候,就是你的回收之日。
4.虚引用
这个引用对它指向的对象不会产生任何影响,只是当这个对象被回收时,发出系统通知。
回收方法区
上面的算法回收的对象都是堆,而方法区也需要回收,但是回收方法区的效率很低,因为方法区太小了~~
方法区相当于堆的逻辑部分,堆存放的时对象实例,而方法区存放的时它的类信息,常量,所以gc回收的是无用的类和无用的常量。
回收方法:
1.无用常量:没对象引用它就回收。
2.无用类:堆不存在它的实例,加载它的ClassLoader回收了,它的Class对象没有被引用,满足以上三个条件,它就是无用类,可以被回收了。