强引用
只有所有GC Roots对象都不通过`强引用`引用该对象,该对象才能被垃圾回收
软引用(SoftReference)
仅有软引用引用该对象时,在垃圾回收后,内存任不足时会再次发出垃圾回收, 回收软引用对象.
可以配合引用队列来释放软引用本身
代码示例
// -Xmx20m -XX:+PrintGCDetails -verbose:gc
public class Test2 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new byte[_4MB]);
}
}
}
这里我们设置了堆内存为20m,我们循环往里面丢4m大小的byte因为都是强引用所以发生了内存溢出
下面我们利用软引用来解决强引用发生的内存溢出问题
// -Xmx20m -XX:+PrintGCDetails -verbose:gc
public class Test2 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
System.out.println("循环结束:"+list.size()+"=================================");
System.out.println("打印数组");
for (SoftReference<byte[]> reference : list) {
System.out.println(reference.get());
}
}
}
一共gc了4次,发现并没有发生内存溢出,但是集合里面的对象已经前4个都是null了
配合引用队列释放软引用本身
// -Xmx20m -XX:+PrintGCDetails -verbose:gc
public class Test2 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<SoftReference<byte[]>> list = new ArrayList<>();
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
// 关联了引用队列,当软引用对象关联的对象被回收时,软引用自己会加入queue队列去
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB],queue);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
Reference<? extends byte[]> poll = queue.poll();
while (poll!=null){
list.remove(poll);
poll=queue.poll();
}
System.out.println("循环结束:"+list.size()+"=================================");
System.out.println("打印数组");
for (SoftReference<byte[]> reference : list) {
System.out.println(reference.get());
}
}
}
发现引用本身也没清理出集合了
弱引用(WeakReference)
仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
代码和软引用差不多
// -Xmx20m -XX:+PrintGCDetails -verbose:gc
public class Test2 {
private static final int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) {
List<WeakReference<byte[]>> list = new ArrayList<>();
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
// 关联了引用队列,当软引用对象关联的对象被回收时,软引用自己会加入queue队列去
WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB],queue);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
Reference<? extends byte[]> poll = queue.poll();
while (poll!=null){
list.remove(poll);
poll=queue.poll();
}
System.out.println("循环结束:"+list.size()+"=================================");
System.out.println("打印数组");
for (WeakReference<byte[]> reference : list) {
System.out.println(reference.get());
}
}
}
虚引用
虚引用,对一个对象而言,这个引用形同虚设,有和没有一样,如果一个对象与GC Roots之间仅存在虚引用,则称这个对象为虚可达(phantom reachable)对象,必须配合引用队列使用,它的作用在于跟踪垃圾回收过程,主要配合ByteBuffer使用来释放直接内存
cleaner对象正是一个虚引用对象
通过监控对象的回收来处理直接内存的释放