在Java中怎么可以看一个对象是不是垃圾对象
文章目录
- 在Java中怎么可以看一个对象是不是垃圾对象
- 第一、引用计数法
- 第二、可达性分析算法
- 第三、四种引用
- 1、强引用
- 2、软引用
- 3、弱引用
- 4,虚引用
- 还有一种就是重写Object类的finallized()方法(终结器引用)
如何判断一个对象是不是垃圾对象
第一、引用计数法
引用计数描述的算法为:|
给每一个对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任
何时刻计数器为0的对象就是不能再被使用的,即对象已"死"。
引用计数法实现简单,判定效率也比较高,在大部分情况下都是一个不错的算法。
但是,在主流的JVM中没有选用引用计数法来管理内存,最主要的原因就是引用计数法无法解决对象的
循环引用问题。
public class Test {
public Object instance = null;
private static int _1MB = 1024 * 1024;
private byte[] bigSize = new byte[2 * _1MB];
public static void testGC() {
Test test1 = new Test();
Test test2 = new Test();
test1.instance = test2;
test2.instance = test1;
test1 = null;
test2 = null;
//强制进行垃圾回收
System.gc();
}
public static void main(String[] args) {
testGC();
}
}
注意,在Java中垃圾回收会回收两个互相引用的对象的,因为Java虚拟机不是用的引用计数算法来判断对象是否死亡。
第二、可达性分析算法
可达性分析算法也是可以判断对象是否死亡
先来说一下什么是GC roots?
GC roots就是来判断是否为垃圾对象的,通俗一点来说:就是GC roots的对象以及被GC roots 引用的对象都不是垃圾对象,其他的对象都是垃圾对象。
此算法的核心思想为 : 通过一系列列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索
走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的
哪些对象可以作为GC roots对象呢?
1.虚拟机栈(栈帧中的本地变量表)中引用的对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈中JNI(Native方法)引用的对象|
注意:并不是栈中的引用可以作为GC roots,而是栈中引用所指向的对象可以作为GC roots对象。
第三、四种引用
在Java中引用分为四种引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用的强度依次递减。
1、强引用
强引用指的是在程序代码之中普遍存在的,类似于"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象实例。
只要被GC roots 直接引用的或者间接引用的都是强引用。
2、软引用
软引用是用来描述一些还有用但不是必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了了SoftReference类来实现软引用。
简单的说:就是第一次进行垃圾回收之后,内存还是不够的情况下,会进行二次回收,第二次会把软引用的对象进行回收,如果第二次回收之后,内存还是不够,就会抛出异常。
3、弱引用
弱引用也是用来描述非必需对象的。但是它的强度要弱于软引用。被弱引用关联的对象只能生存到下一次垃圾回收发生之前。当垃圾回收器开始进行工作时,无论当前内容是否够用,都会回收掉只被弱引用关联的对象。在JDK1.2之后提供了了WeakReference类来实现弱引用。
简单的说:被弱引用引用的对象每次垃圾回收都会被回收掉
4,虚引用
虚引用:最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的唯一目的就是能在这个对象被收集器器回收时收到一个系统通知。在JDK1.2之后,提供了了PhantomReference类来实现虚引用。
注意:虚引用的对象被回收时,并不会回收分配到直接内存,所以就会将虚引用放置引用队列中,会有一个专门的线程会定时查看引用队列有没有引用,如果有就会释放该虚引用的内存地址,从而释放直接内存。
还有一种就是重写Object类的finallized()方法(终结器引用)
终结器引用:当对象没有被强引用引用时,并且该对象重写了finallized()方法,该对象并不会直接被回收,而是将该引用放到引用队列中,就会有一个Finallizer线程来进行处理,但是该线程的优先级太低,一般被系统调度的几率小,如果还没释放对象之前,该对象被重新引用时,该引用就不会在引用队列中,该线程进行清除时,就会调用该对象的finallized()方法,这时候对象才是真正的死亡。
注意:finallized()方法只会被调用一次。