Java设计这四种引用的主要目的
1、可以让程序员通过代码的方式来决定某个对象的生命周期。
2、有利用垃圾回收。
强引用
package com.test;
public class Test {
private String a;
public String getA() {
return this.a;
}
public void setA(String a) {
this.a = a;
}
public static void main(String[] args) {
Test t = new Test();
t.setA("args");
System.out.println(t.getA());
}
}
Test t = new Test();
我们日常代码中99.999%都是强引用
只要某个对象有强引用与之关联,那么这个对象永远不会被回收,就算内存不足,JVM宁愿抛出OOM,也不会去回收
不过,当强引用和对象之间的关联被中断了,就可以被回收了。
我们可以手动把关联给中断了
t = null;
软引用
软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了:
SoftReference<Test> testSoftReference = new SoftReference<Test>(new Test());
Test t = testSoftReference.get();
当内存不足,会触发GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给回收掉否则不会回收
例:
先设置参数-Xmx10M 表示最大堆内存为10M
可以看到,第一次gc后,没被回收,因为内存才用了5M(多些)
接着 byte[] bytes = new byte[1024 * 1024 * 5];
加起来内存不够了,就被回收了,打印出null。
弱引用
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024\*1024\*10]);
System.out.println(weakReference.get());
不管内存是否足够,只要发生GC,都会被回收
弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。
虚引用
又称幻影引用
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
System.out.println(reference.get());
例:
protected void finalize()throws Throwable {
System.out.println("Test 被回收了");
}
public static void main(String[] args) {
ReferenceQueue queue = new ReferenceQueue();
List<byte[]> list = new ArrayList<>();
PhantomReference<Test> reference = new PhantomReference<Test>(new Test(),queue);
new Thread(() -> {
for (int i = 0; i < 100;i++ ) {
list.add(new byte[1024 * 1024]);
}
}).start();
new Thread(() -> {
while (true) {
Reference poll = queue.poll();
if (poll != null) {
System.out.println("虚引用被回收了:" + poll);
}
}
}).start();
Scanner scanner = new Scanner(System.in);
scanner.hasNext();
}
第一个线程往集合里面添加数据,随着数据越来越多,肯定会发生GC。
第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。
从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。
在NIO中,就运用了虚引用管理堆外内存.