Java有四种引用:强、软、弱、虚,一个变量指向new出来的对象,这就叫一个引用,不同的引用再JVM进行GC时会有不同的表现。如下代码重写了对象的finalize()方法,当该对象被虚拟机GC时,会调用该方法。在平时编程过程中,不能重写该方法,也不要自行调用该方法。
public class M {
@Override
protected void finalize() throws Throwable {
// super.finalize();
System.out.println(“finalize”);
}
}
强引用:
普通的引用比如:Object o = new Object(),这个就叫强引用。只要强引用存在,该引用指向的对象就不会被虚拟机回收。
public class StrongReference {
public static void main(String[] args) throws IOException {
M m = new M();
System.gc();
System.out.println("引用指向null");
m = null;
System.gc();
System.in.read();
}
}
// 输出结果:
引用指向null
finalize
软引用:
当有一个对象被软引用所指向的时候,只有系统内存不够用的时候,才会回收它。如下程序将堆大小设置为20M,首先new一个10M字节数组对象,并用一个虚引用指向它。当堆内存足够时,该对象不会被回收,但是又new了一个15M的字节数组后,由于堆空间不足,该对象被虚拟机回收。
public class Softrefrence {
public static void main(String[] args) {
SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
System.out.println(m.get());
System.gc();
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(m.get());
byte[] b = new byte[1024*1024*15];
System.out.println(m.get());
}
}
// 输出结果:
[B@511d50c0
[B@511d50c0
null
弱引用:
当有一个对象被弱引用所指向的时候,只要虚拟机GC就会回收它。
public class Weakrefrence {
public static void main(String[] args) throws InterruptedException {
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc();
Thread.sleep(500);
System.out.println(m.get());
}
}
// 输出:
M@511d50c0
finalize
null
虚引用:
虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个。一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例。
public class Phantomreference {
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<M> m = new PhantomReference<>(new M(),QUEUE);
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(m.get());
}
}).start();
new Thread(()->{
while (true){
Reference<? extends M> poll = QUEUE.poll();
if (poll!=null){
System.out.println("---虚引用对象被JVM回收---"+poll);
}
}
}).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
null*n
finalize
null
---虚引用对象被JVM回收---java.lang.ref.PhantomReference@356c6d9c
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会彻底销毁该对象。所以可以通过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。虚引用有一个很重要的用途就是用来做堆外内存的释放,DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。