【JAVA 基础】JAVA 四种引用(强软若虚)
【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 之类方法回收掉堆外内存
摘抄自网络,便于检索查找。