java四大引用

116 阅读4分钟

1·为什么要用Java引用 2·java引用有哪几种 3·每种引用的特点是什么 4·它们各自的应用场景有哪些

从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期,JVM 是通过垃圾回收器GC对这四种引用做不同的处理,来实现对象生命周期的改变。

1·设计目的:

  1. 可以让程序员通过代码来决定某一个对象的生命周期
  2. 更有利于垃圾回收

2·四种引用类型

image.png

垃圾回收器,也叫GC,主要有以下特点:

  • 1·段落引用- 当对象不在被程序使用的时候,垃圾回收器会将其回收
  • 2·垃圾回收器在回收某一个对象的时候,首先会调用该对象的finalize()方法
  • 3·GC主要针对堆内存

为了以下四种引用的执行,定义一个finalize类:

package YingYong;
/**
 * @author 宋治泽
 */

public class MyReference {
    @Override
    protected void finalize() {
        //finalize 方法,当这个对象被回收的时候,finalize方法会被调用
        System.out.println("回收成功");
    }
}

1. 强引用

什么是强引用?

++最普通的引用,把一个对象赋值给一个引用变量,这个引用变量就是强引用++

MyReference m = new MyReference();

如果一个对象中有强引用,当JVM内存不够时,JVM宁愿抛出OOM异常也不会对强引用变量进行回收

回收时刻:

  1. 1·强引用被赋值为null;
  2. 2·没有了其他的引用关系,超过了引用的作用域
package YingYong;

import java.io.IOException;

/**
 * @author 宋治泽
 */

public class NormalReference {
    public static void main(String[] args) throws IOException {
        //强引用:一个普通的变量,指向一个对象,然后对象引用消失的时候,视为被废弃的对象,属于被回收的范围,该对象的所有成员变量也随之被回收
        MyReference  m = new MyReference( );

        //当m=null没有标注的时候,强引用是不会被回收的
	//m=null;

        //启用垃圾回收,并不是在main方法里回收垃圾,而是在垃圾回收线程里面,存在一种可能就是垃圾回收线程环没有回收完,
        //main方法就已经结束,会看不到结果,所以写下面的代码
        System.gc();
        System.out.println("回收不成功");

        //阻塞一下main方法,如果不写这句代码,整个main方法就会退出
        System.in.read();
    }
}

2. 软引用

什么是软引用?

++级别仅次于强引用,软引用通过SoftReference类来实现。当JVM堆内存充足时,和我们在内存里面分配一个对象是一样的,但是当有了新的对象往内存里分配,但是内存不足时,软引用就会被回收。++ image.png

注意:

软引用用来描述一些有用但是非必须的对象,对于软引用关联着的对象,在系统即将发生内存溢出异常之前,将会把这些对象列入回收的范围进行二次回收,倘若这次回收JVM堆内存不足,才会抛出内存溢出异常。

package YingYong;
/**   软引用     --是个对象
*   -Xmx20M jvm堆最大可使用内存20M
* @author 宋治泽*/

public class SoftReference {
    public static void main(String[] args) {
        //m指向正常的对象SoftReference,在SoftReference中含有一个引用,这个引用是软引用,指向字节数组(内存大小10M)
        java.lang.ref.SoftReference<byte[]> m = new java.lang.ref.SoftReference<>(new byte[1024 * 1024 * 10]);

        //m = null;
        //软引用指向的对象
        System.out.println(m.get());


       //回收一下
        System.gc();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //如果软引用被回收了,那么get是get不到的
        System.out.println(m.get());

        //再分配一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用回收
        //这是一个强引用,但是软引用占了内存10M,会导致空间太满而存放不下
        //内存12M
        byte[] b = new byte[1024 * 1024 * 12];
        System.out.println(m.get());
    }
}

实际应用

  • 适合用于缓存,当我们存放一张图片的时候,当内部够用的时候,对这个图片进行展示,有更重要的文件存储的时候,内存不够了,就可以使用软引用,对图片先进行GC,以便于重要文件的存储

3. 弱引用

什么是弱引用?

++弱引用和软引用类似,只是关键字变成了WeakReference和软引用有所不同的是,弱引用不管内存是不是充足,够不够下一个对象存储,只要发生GC,都会被回收。++

package YingYong;

/**   弱引用遭到GC就会回收
*     弱引用的使用场景:解决某些地方的内存泄漏问题
*     @author 宋治泽*/

public class WeakReference {
    public static void main(String[] args) {
        java.lang.ref.WeakReference<MyReference> m = new java.lang.ref.WeakReference<>(new MyReference());

        //拿m的值
        System.out.println(m.get());
        System.gc();//对弱引用对象进行回收
        //继续拿m的值
        System.out.println(m.get());
        //以上三句代码可以看出,弱引用遇到GC就会被回收

    }
}

4. 虚引用

简单概念:

++又叫幻想引用,通过PhantomReference类来实现。++

和其他引用不同的是,虚引用不会决定对象的生命周期,如果一个对象之中有虚引用存在,那么他就和没有任何引用一样,任何时候都可能被垃圾回收器回收。

package YingYong;

import java.lang.ref.ReferenceQueue;
/**
 @author 宋治泽
 */

public class PhantomReference {
    public static final ReferenceQueue QUEUE = new ReferenceQueue<>();
    public static void main(String[] args) {
        Object o1 = new Object();
//        ReferenceQueue<Object> r = new ReferenceQueue<>();
        java.lang.ref.PhantomReference<MyReference> m = new  java.lang.ref.PhantomReference<>(new Object(),QUEUE);
        System.out.println("-----------GC回收前--------------");
        System.out.println(o1);
        System.out.println(m.get());
        System.out.println(QUEUE.poll());

        System.out.println("___________________启动GC___________________");
        o1 = null;
        System.gc();
        try {
            //确保GC都执行完了
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(o1);
        System.out.println(m.get());
        System.out.println(QUEUE.poll());

    }
}

用途:

主要用来跟踪对象被垃圾回收器回收的活动。

注意事项:

  • 虚引用需要和引用队列(ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象的时候,如果发现此时这个对象有虚引用的存在,就会在GC之前,把虚引用加入到与之关联的引用队列当中。

3·总结

类型回收时间用途生存时间
强引用从来不会对象的一般状态下JVM停止运行的时候
软引用内存不足的时候对象缓存内存不足的时候
弱引用GC时对象缓存GC运行之后
虚引用Unkown跟踪对象被垃圾回收器回收的活动Unkown