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

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

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

强引用

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

软引用

  • -Xmx10m // 配置最大堆内存为 10MB
Copy
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 是不直接回收弱引用的,只有等堆内存不够了,才会回收前面分配的这些对象
  • 软引用用的不多

弱引用

Copy
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,方便下次回收。不过这个存在的问题就是如果不执行的话那么就会一直存在,依赖于用户

虚引用

Copy
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 @ 2024-06-26 18:55  CharyGao  阅读(0)  评论(0编辑  收藏  举报