Java中的引用类型
首先java中的引用类型有如下几种:强引用,软引用,弱引用,虚引用。
接下来会结合代码尝试着对这几种引用类型做下讲解。
测试四种引用类型
首先,我们创建了这样一个类:
public class Test1 {
@Override
protected void finalize()throws Throwable{
System.out.println("finalize发生 ");
}
}
重写了finalize方法 这样在Test1垃圾回收时会调用这个方法
强引用
我们平时使用的new对象的形式就是强引用
public class main {
public static void main(String[] args) {
Test1 t1 = new Test1();
t1 = null;
System.gc();
System.out.println("t1 = " + t1);
}
}
结果:
仅当对象不被引用指向时,对象被当作垃圾清空,触发finalize方法。
软引用
public class Test2 {
public static void main(String[] args) {
SoftReference<byte[]> test = new SoftReference<>(new byte[1024*1024*15]);
System.out.println("第一次调用" + test.get());
System.gc();
try{
Thread.sleep(500);
}catch (Exception ee){
ee.printStackTrace();
}
System.out.println("第二次调用" + test.get());
byte[] test2 = new byte[1024*1024*20];
System.out.println("第三次调用" + test.get());
}
}
我们在运行这个程序之前先在VM option中输入参数“-Xmx30M”,意思是设置堆的最大内存为30M
结果:
此时我们发现 前面两次调用都成功了,但是最后一次没有成功。这样的原因是,软引用会在内存发生溢出之前,它就会被回收,所以软引用很适合作为缓存使用。
弱引用
import java.lang.ref.WeakReference;
public class Test3 {
public static void main(String[] args) {
WeakReference<Test1> w = new WeakReference<>(new Test1());
System.out.println("第一次调用:" + w.get());
System.gc();
System.out.println("第二次调用:" + w.get());
}
}
结果:
我们能够发现,一旦经过一次gc,那么弱引用就会被清理。
虚引用
一般我们不会使用虚引用,运行时设置参数“-Xmx20M”.
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;
public class Test4 {
private static final List<Object> List = new LinkedList<>();
private static final ReferenceQueue<Test1> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<Test1> phantomReference = new PhantomReference<>(new Test1(),QUEUE);
System.out.println(phantomReference.get());
new Thread(() -> {
while(true){
List.add(new byte[1024*1024]);
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println(phantomReference.get());
}
}).start();
new Thread(() -> {
while(true){
Reference<? extends Test1> poll = QUEUE.poll();
if(poll != null){
System.out.println("虚引用对象被回收");
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
虚引用从头到尾无论是否gc都无法get到,当虚引用对象被清理时,会被放到队列中。一般虚引用用来垃圾回收时给系统一个通知。这里的应用场景是用于管理堆外内存。
总结
- 强引用:发生 gc 的时候不会被回收。
- 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
- 弱引用:有用但不是必须的对象,在下一次GC时会被回收。
- 虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。