【JAVA基础】JAVA四种引用(强软若虚)

  • java中有四种引用类型,分别是

强引用

  • 强引用也就是我们通常认为的java中的中的引用关系
  • 通过new创建一个对象,然后赋值给一个变量,这个时候这个变量指向堆中地址的引用就是一个强引用
  • 他收到JVM的管理,当JVM发生GC的时候,如果有强引用指向了空的话,那么这个时候GC就会对这类对象进行进行回收

软引用

  • -Xmx10m // 配置最大堆内存为10MB
import java.lang.ref.SoftReference;

public class MyReference {

    public static void main(String[] args) throws InterruptedException {
        // int占用4个字节,创建一个5MB大小的数组
        SoftReference softReference = new SoftReference(new int[5 * 1024 * 1024 / 4]);
        System.out.println(softReference.get());
        System.gc();
        Thread.sleep(2000);
        System.out.println(softReference.get());
        SoftReference softReference1 = new SoftReference(new int[1024 * 1024 / 4]);
        System.out.println(softReference.get());
        System.out.println(softReference1.get());
    }

}
  • 软引用通过SoftReference来指向
  • GC是不直接回收弱引用的,只有等堆内存不够了,才会回收前面分配的这些对象
  • 软引用用的不多

弱引用

import java.lang.ref.WeakReference;

public class MyReference {

    public static void main(String[] args) {
        WeakReference weakReference = new WeakReference(new Object());
        System.out.println(weakReference.get());
        System.gc();
        System.out.println(weakReference.get());
    }

}
  • 弱引用的话会如果发生GC的话会直接断开
  • ThreadLocal里面就是用到了弱引用,是这样用的

ThreadLocal用来保存线程独有的信息,可以get/set一个值,这个值是一个泛型,可以自己指定

  • ThreadLocal不是所有线程共享一个变量,里面是一个map,key是Thread,value是值,而是每个线程有自己的ThreadLocalMap,map里面存的是<ThreadLocal,Value>
  • Thread里面有一个ThreadLocal.ThreadLocalMap变量,之所以这样是好维护
  • ThreadLocalMap里面是一个个Entry,Entry的key是ThreadLocal,而且是一个弱引用,在每次GC的时候如果就会GC(如果没有强引用的时候)
  • 但是依然会有内存泄漏的问题,key对应的ThreadLocal可能GC了,但是Entry不会GC,不过JDK开发人员早考虑到了,在get和set方法的时候会判断key为null的情况,如果是的话把entry就设置为null,方便下次回收。不过这个存在的问题就是如果不执行的话那么就会一直存在,依赖于用户

虚引用

public static void main(String[] args) {
    ReferenceQueue<Object> queue = new ReferenceQueue<>();
    PhantomReference phantomReference = new PhantomReference(new Object(),queue);
    System.gc();
    System.out.println(phantomReference.get());
    System.out.println(queue.poll());
}

虚引用的通过get方法是获取不到的,主要用来在对象回收以后获得通知的。

  • 虚引用会用在直接内存中使用,直接内存为了减少内存拷贝的问题,不管网络中的数据还是数据库或者磁盘中的数据,都要先读到内存再进入jvm内存,jvm才可以操作。在netty或jdk中DirectByteBuffer都使用到了,但是问题是直接内存不属于JVM运行时内存,GC算法不会直接处理,其实就是通过DirectByteBuffer虚引用指向了堆外内存,等堆内引用消失以后会通过JNI之类方法回收掉堆外内存
posted @ 2020-08-05 14:31  colin_xun  阅读(177)  评论(0编辑  收藏  举报