【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之类方法回收掉堆外内存