1,强引用
默认的引用关系,只有对象没有任何强引用时才会被回收。
下图表示a强引用到一个新的对象。
public class M {
@Override
protected void finalize() throws Throwable {
//该方法不推荐使用,我们只是用来测试引用类型,该方法调用时机和是否一定会被调用不确定
System.out.println("M被回收!!!");
}
}
public class StrongRefTest {
public static void main(String[] args) throws IOException {
M m = new M();
//引用断开
m = null;
//显式进行gc操作
System.gc();
防止main退出
System.in.read();
}
}
2. 软引用
软引用是当jvm内存不够时,会自动回收软引用对象
以下代码运行在jvm大小为20M的场景下:-Xmx20M
public class SoftRefTest {
public static void main(String[] args) throws InterruptedException {
//创建软引用,数组大小10M
SoftReference<byte[]> m = new SoftReference<>(new byte[1024 * 1024 * 10]);
//1.软应用指向的对象为里面的数组对象
System.out.println(m.get()); //[B@63961c42
//2.显式gc,不会造成软引用回收
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(m.get()); //[B@63961c42
//3.申请另一块大小为12M的空间。这时由于超过了JVM设置的堆大小( 12M + 10M = 22M > 20m),软应用被回收
byte[] b = new byte[1024 * 1024 * 12];
System.out.println(m.get()); //null
}
}
适合使用在缓存场景下
3. 弱引用
弱引用在任何一次gc后就会被回收
public class WeakRefTest {
public static void main(String[] args) throws InterruptedException {
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(m.get());
}
}
主要用于解决内存泄漏问题
4. 虚引用
用于管理对外内存
public class PhantomRefTest {
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) throws InterruptedException, IOException {
PhantomReference<M> m = new PhantomReference<>(new M(), QUEUE);
new Thread( () -> {
while(true){
LIST.add(new byte[1024 * 1024]);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//任何时候拿到的都是null
System.out.println(m.get());
}
}).start();
new Thread( () -> {
while (true) {
Reference<? extends M> poll = QUEUE.poll();
if(poll != null){
System.out.println("虚引用对象被回收!!!");
}
}
}).start();
while (true) {
}
}
}