注:基于 jdk11
引用类型
强引用
软引用
弱引用
虚引用
概念
强引用
默认情况下,new 一个对象,并将其引用赋值给一个变量,即为强引用。
import java.util.Arrays;
import java.util.Comparator;
public class M {
@Override
protected void finalize() {
System.out.println("finalize");
}
public static void main(String [] args) {
int x= Arrays.asList(new Integer[]{1,3,4,5}).stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
}).get();
System.out.println(x);
}
}
package chapter06;
import java.io.IOException;
/**
* 强引用,是默认的引用,也就是强引用。
* 只要有一个引用指向这个对象,那么这个对象就不是垃圾,一定不会被垃圾回收器回收,
* 只有没有引用指向它时才会被垃圾回收期择机回收。
*/
public class T01_NormalReference {
public static void main(String [] args) throws IOException {
M m = new M();
System.gc();
m = null;
System.out.println("before gc");
System.gc();
System.out.println("after gc");
System.in.read();
}
}
复制代码
执行结果如下:
before gc
after gc
finalize
软引用
gc()不会直接回收,只有在需要分配内存不够的情况下被回收
package chapter06;
import java.io.IOException;
import java.lang.ref.SoftReference;
/**
* 软引用,gc()不会直接回收,只有在需要分配内存不够的情况下被回收
*/
public class T01_SoftReference {
public static void main(String [] args) throws IOException, InterruptedException {
SoftReference<byte []> m = new SoftReference<>(new byte[1024*1024*10]);
System.out.println(m.get());
System.gc();
Thread.sleep(500);
System.out.println(m.get());
byte [] b = new byte[1024*1024*15];
System.out.println(m.get());
}
}
复制代码
执行结果如下:
[B@6bdf28bb
[B@6bdf28bb
null
弱引用
引用存在的情况下,只要 gc()直接回收
package chapter06;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
/**
* 弱引用,引用存在的情况下,只要gc()直接回收
*/
public class T01_WeakReference {
public static void main(String [] args) throws IOException, InterruptedException {
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc();
System.out.println(m.get());
ThreadLocal tl = new ThreadLocal();
tl.set(new M());
tl.remove();
}
}
复制代码
执行结果如下:
chapter06.M@6b71769e
null
finalize
虚引用
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用必须和 ReferenceQueue 联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的 ReferenceQueue 中。
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.List;
/**
* 虚引用,get不到
* 作用,管理堆外内存,DirectBuffer
* 垃圾回收器,有一个专门的gc回收线程,通过虚引用管理堆外内存
*/
public class T01_PhantomReference {
public static final List<Object> LIST = new LinkedList<>();
public static final ReferenceQueue queue = new ReferenceQueue();
public static void main(String [] args) throws IOException, InterruptedException {
PhantomReference<M> m = new PhantomReference<>(new M(), queue);
new Thread(()->{
while(true) {
LIST.add(new byte[1024*1024*10]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1" + m.get());
}
}).start();
new Thread(() -> {
while(true) {
Reference reference = queue.poll();
if (reference != null) {
System.out.println("2" + reference);
}
}
}).start();
System.in.read();
}
}
复制代码
执行结果如下:
1null
1null
1null
1null
1null
1null
1null
1null
finalize
1null
2java.lang.ref.PhantomReference@457582f7
1null
1null
1null
1null
1null
1null
1null
1null
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
at chapter06.T01PhantomReference.lambda$main$0(T01PhantomReference.java:26)
at chapter06.T01_PhantomReference$$Lambda$14/0x0000000800066840.run(Unknown Source)
at java.base/java.lang.Thread.run(Thread.java:834)
扩展
ThreadLocalMap
ThreadLocalMap 的 Entry 继承了 WeakReference,且 Entry 的 Key(ThreadLocal)是弱引用。ThrealLocal 其实就是对 ThreadLocalMap 的操作封装。如果 heap 不足,gc 的时候 key 会被回收掉,出现 Entry<null, obj>的情况,等下次 gc 下次回收会把 Entry<null, obj> 回收。所以 ThreadLocal 的正确使用方法是用完要 remove(),避免内存泄漏。
评论