简介
JVM会在必要时启动垃圾回收,为了方便我们控制对象的生命周期,
从JDK1.2(记错了给我说)开始有四种引用类型,强引用>软引用>弱引用>虚引用。
引用在栈内存中,真实的对象在堆内存中。
栈内存中的东西是某线程独享。
堆内存中的东西是可所有线程共享的。
一、强引用(StrongReference)
一个对象只要有强引用存在,Java GC就不会回收它,无论内存有多紧张,这也是可能发生内存泄漏的一个点。
强引用的声明就是我们最常用的直接new一个对象,比如:
Student s = new Student()
1.如果上述的Student s = new Student()是在一个方法中定义的,比如方法A。
那么方法A执行完成后,会退出方法栈,该Student的引用就不会存在了, 堆内存中Student的真实对象由于没有了引用,就会被GC回收。
2.如果上述的Student s = new Student()是一个全局变量,用完后需要手动置空。
否则GC不会回收它。
s = null;
3.注意当它是集合的时候
List<Student> list = new ArrayList();
ArrayList.clear()方法源码
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
也就是说调用list.clear()只是把集合内每一个元素设置为=null,这个跟 list=null是不一样了,此时list的强引用还在,为下次add操作做准备,这里只是释放了list中每个元素的引用,并不是释放list本身的引用。
同理在使用map的时候也要注意这个问题,key=null或value=null,跟map本身=null是不一样的。比如ThreadLocalMap的内存泄漏问题。
二、软引用(SoftReference)
如果一个对象只有软引用存在,那么内存空间足够的时候,GC不会回收它。
只有当内存空间不足的时候,GC才会去回收软引用对象。
软引用可以和一个引用队列(ReferenceQueue)联合使用。
软引用可用来实现内存敏感的高速缓存。
声明方式:
SoftReference<Student> s = new SoftReference<>(new Student());
三、弱引用(WeakReference)
一个只具有弱引用的对象,只要垃圾回收的线程发现它,就会回收它,无论内存空间是否足够。
但是垃圾回收线程是一个优先级很低的线程,所以不会很快发现弱引用。
弱引用也可以和一个引用队列(ReferenceQueue)联合使用。
如果一个对象只是偶尔使用,且在要使用的时候又能取到,又不想影响该对象的垃圾回收,那么就可以用弱引用。
声明方式:
WeakReference<Student> s = new WeakReference<>(new Student());
四、虚引用(PhantomReference)
一个只具有虚引用的对象,它就跟没有引用一样,随时可能被GC回收。
虚引用必须和引用队列(ReferenceQueue)联合使用。
引用队列:
如果引用的对象被GC回收,JVM会把这个软引用对象加入到与之相关联的引用队列中去,这样在可触及性发生变化的时候得到“通知”。比如用虚引用做缓存,查看引用队列中是否有目标,在发现JVM要回收它的时候再重新申请内存空间。
虚引用可用来跟踪对象被GC回收的活动。
声明方式及操作引用队列的示例:
package com.sid.reference;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;
/**
* @program: thread-test
* @description:
* @author: Sid
* @date: 2018-11-26 16:21
* @since: 1.0
**/
public class PhantomReferenceTest {
public static boolean isRun = true;
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Student> referenceQueue = new ReferenceQueue<>();
new Thread() {
public void run() {
while (isRun) {
Object obj = referenceQueue.poll();
if (obj != null) {
try {
Field rereferent = Reference.class
.getDeclaredField("referent");
rereferent.setAccessible(true);
Object result = rereferent.get(obj);
System.out.println("gc will collect:"
+ result.getClass() + "@"
+ result.hashCode() + "\t"
+ (Student) result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}.start();
Student student = new Student();
PhantomReference<Student> referent = new PhantomReference<>(student,referenceQueue);
student = null;
Thread.currentThread().sleep(3000);
System.gc();
Thread.currentThread().sleep(3000);
isRun = false;
}
}