Java里面的四种引用:强引用,软引用,弱引用,虚引用

在垃圾回收的时候,被释放的对象要考虑什么样的对象内存要被GC回收掉,那么怎么判断哪些对象要被回收掉呢,在java里面定义了四种引用对象,不同的引用对象在被GC扫描的时候,会有不同的处理方式,这里我们来看一下

强引用

强引用介绍

强引用是用来描述必须存在和引用的对象,比如Object a=new Object(),只要强引用还存在,被引用的对象就永远不会被回收。

强引用怎么被垃圾回收

方法里面的局部变量强引用被垃圾回收:
在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。

public void test(){
	Object o=new Object();
	// 省略其他操作
}

成员变量的强引用被垃圾回收
此时在使用完设置null就好了,就是使用下面的蓝色代码进行垃圾回收

Object o;
public void test(){
	o=new Object();
	// 省略其他操作
     o=null;
}

软引用

软引用什么时候会被回收

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

###正因为软引用只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。

Browser prev = new Browser();               // 获取页面进行浏览
//进行页面浏览操作
SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用		
if(sr.get()!=null){ 
	rev = (Browser) sr.get();           // sr.get()返回值就是软引用指向的对象,如果不为null,那就表示还没有被回收器回收,直接获取
}else{
	prev = new Browser();               // 如果sr.get()返回值是null,那么由于内存吃紧,所以jvm就会对软引用的对象回收了
	sr = new SoftReference(prev);       // 对于已经回收的对象,在重新构建软引用
}

软引用可以通过SoftReference类来实现
如下所示

package com.hello;

import java.lang.ref.SoftReference;

public class Test {
    public static void main(String[] args)  {
        String str = new String("软引用实现啦");
        SoftReference<String> hello = new SoftReference<>(str);
        String s = hello.get();
        System.out.println(s);
    }
}

结果如下所示

软引用实现啦

弱引用

弱引用介绍

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用通过WeakReference来实现
如下所示

package com.hello;

import java.lang.ref.WeakReference;

public class Test {
    public static void main(String[] args)  {
        String str = new String("弱引用实现啦");
        WeakReference<String> hello = new WeakReference<>(str);
        String s = hello.get();
        System.out.println(s);
    }
}

结果如下所示

弱引用实现啦

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中
代码如下所示

package com.hello;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class Test {
    public static void main(String[] args)  {
        String str = new String("str");
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
        WeakReference<String> hello = new WeakReference<>(str, referenceQueue);
        new Thread(() -> {
            while (true) {
                if (hello.isEnqueued()) {
                    System.out.println("弱引用垃圾回收了");
                }
            }
        }).start();
        str = null;
        System.gc();
    }
}

结果如下所示

弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了
弱引用垃圾回收了

虚引用和弱引用的区别

  1. 弱引用应该还可以通过引用来获取对象,但是虚引用根本获取不到对象
  2. 虚引用存在于每一个对象里面,不会对对象的存活造成任何影响,唯一用处就是唯一的用处:能在对象被GC时收到系统通知

虚引用

什么是虚引用

也称为幻影引用:一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知,JAVA中用PhantomReference来实现虚引用。

虚引用和弱引用的区别

  1. 弱引用应该还可以通过引用来获取对象,但是虚引用根本获取不到对象
  2. 虚引用存在于每一个对象里面,不会对对象的存活造成任何影响,唯一用处就是唯一的用处:能在对象被GC时收到系统通知

虚引用怎么进行垃圾回收的通知

在留言栏里面看到@Super_Jingjun 同学的疑问,所以这里我又在网上查找了虚引用到底怎么做垃圾回收的通知,最后找到:

1.PhantomReference的get()方法的返回值是null(这个是源码里面看到的),所以根本不能通过PhantomReference的get()方法是否是null来判断虚引用的对象是否被回收了,这个要注意一下。
2.当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列(这个队列就是ReferenceQueue队列)中,所以可以通过PhantomReference类的父类的Reference方法的isEnqueued()方法来判断虚引用指向的对象是否被回收了(isEnqueued()方法只会在虚引用指向的对象加入到与之关联的队列里面才会返回true)。

代码如下所示

package com.hello;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class Test {
    public static void main(String[] args)  {
        String str = new String("str");
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
        PhantomReference<String> hello = new PhantomReference<>(str, referenceQueue);
        new Thread(() -> {
            while (true) {
                if (hello.isEnqueued()) {
                    System.out.println("虚引用垃圾回收了");
                }
            }
        }).start();
        str = null;
        System.gc();
    }
}

结果如下所示

虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了
虚引用垃圾回收了

大佬网址:
https://www.itqiankun.com/article/1564535152
https://juejin.im/post/5ab4691a51882555825249de
https://blog.csdn.net/mazhimazh/article/details/19752475
https://www.zhihu.com/question/37401125

你可能感兴趣的:(#,Jvm,java面试题)