1.强引用
强引用指向的对象,在任何时候都不会被回收。除非将引用置为null
/**
* 强引用
*/
public class StrongReferences {
public static void main(String[] args) {
//创建一个对象,new出来的对象都是分配在java堆中的
Sample sample = new Sample(); //sample这个引用就是强引用
sample = null; //将这个引用指向空指针,
//那么上面那个刚new来的对象就没用任何其它有效的引用指向它了
//也就说该对象对于垃圾收集器是符合条件的
//因此在接下来某个时间点 GC进行收集动作的时候, 该对象将会被销毁,内存被释放
System.gc();
}
}
2.软引用
软引用在java.lang.ref包中有与之对应的类java.lang.ref.SoftReference。
重点: 被软引用指向的对象不会被垃圾收集器收集(即使该对象没有强引用指向它),除非jvm使用内存不够了,才会对这类对象进行销毁,释放内存。
/**
* 软引用
* 软引用在java.lang.ref包中有与之对应的类java.lang.ref.SoftReference。
* 重点: 被软引用指向的对象不会被垃圾收集器收集(即使该对象没有强引用指向它),除非jvm使用内存不够了,才会对这类对象进行销毁,释放内存。
*/
public class SoftReferences {
public static void main(String[] args) throws InterruptedException {
//创建一个软引用指向这个对象,使用-Xmx10m参数,可以将堆内存分配为10M
SoftReference<Sample> softRef = new SoftReference<Sample>(new Sample());
//如果此时堆内存不够用了,软引用指向的对象就会被回收。
List<Object> list = new ArrayList<Object>();
while(true){
/*如果重写了Sample类的finalize方法,内存不足时就可以看到
该方法被调用,说明Sample对象被回收*/
System.out.println(softRef.get());
list.add(new byte[1024 * 1024 * 1]);
Thread.sleep(1000);
}
}
}
3.弱引用
弱引用会被jvm忽略,也就说在GC进行垃圾收集的时候,如果一个对象只有弱引用指向它,那么和没有引用指向它是一样的效果,jvm都会对它就行果断的销毁,释放内存。
如果弱引用指向一个gc root可达的对象,那么该弱引用不会被回收,除非该对象变为可回收对象
其实这个特性是很有用的,jdk也提供了java.util.WeakHashMap这么一个key为弱引用的Map。比如某个资源对象你要释放(比如 db connection), 但是如果被其它map作为key强引用了,就无法被jvm收集。
/**
* 弱引用会被jvm忽略,也就说在GC进行垃圾收集的时候,如果一个对象只有弱引用指向它,那么和没有引用指向它是一样的效果,jvm都会对它就行果断的销毁,释放内存。
* 其实这个特性是很有用的,jdk也提供了java.util.WeakHashMap这么一个key为弱引用的Map。比如某个资源对象你要释放(比如 db connection), 但是如果
* 被其它map作为key强引用了,就无法被jvm收集。
*/
public class WeakReferences {
public static void main(String[] args) throws InterruptedException {
testWeakReferences1();
//testWeakReferences2();
}
/**
* 弱引用会被JVM忽略,直接回收
*/
public static void testWeakReferences1(){
WeakReference<Sample> weakRef = new WeakReference<Sample>(new Sample());
System.out.println(weakRef.get());
//此时只有弱引用指向sample了,sample会被回收
System.gc();
Thread.sleep(2000);
//这里会返回null
System.out.println(weakRef.get());
}
/**
* 弱引用Map
* @throws InterruptedException
*/
public static void testWeakReferences2() throws InterruptedException{
WeakReference<Sample> weakRef = new WeakReference<Sample>(new Sample());
//此处如果使用hashMap,就算使用弱引用,GC也会认为weakRef指向的对象不可回收,不能回收该Key对象
//Map<Sample,String> map = new HashMap<Sample, String>();
//此处如果使用WeakHashMap,Key使用弱引用,而且WeakHashMap的Key是可以回收的,所以weakRef指向的对象会被回收
Map<Sample,String> map = new WeakHashMap<Sample, String>();
map.put(weakRef.get(),"test");
//这里会返回test
System.out.println(map.get(weakRef.get()));
System.gc();
Thread.sleep(2000);
//这里会返回null,说明键已经被回收
System.out.println(map.get(weakRef.get()));
//此处使用WeakHashMap,key是一个对象,但是没有其他引用指向它
//所以会被GC回收,map的长度会变化
Map<Sample,String> map2 = new WeakHashMap<Sample, String>();
map2.put(new Sample(),"test");
//这里返回1
System.out.println(map2.size());
System.gc();
Thread.sleep(2000);
//这里返回0,说明键已经被回收
System.out.println(map2.size());
}
}
4.虚幻引用
虚幻引用和弱引用的回收机制差不多,都是可以被随时回收的。但是不同的地方是,它的构造方法必须强制传入ReferenceQueue,因为在jvm回收前(重点: 对,就是回收前,软引用和弱引用都是回收后),会将PhantomReference对象加入ReferenceQueue中; 还有一点就是PhantomReference.get()方法永远返回空,不管对象有没有被回收。
/**
* 虚引用
* 虚幻引用和弱引用的回收机制差不多,都是可以被随时回收的。但是不同的地方是,它的构造方法必须强制传入ReferenceQueue,
* 因为在jvm回收前(重点: 对,就是回收前,软引用和弱引用都是回收后),会将PhantomReference对象加入ReferenceQueue中;
* 还有一点就是PhantomReference.get()方法永远返回空,不管对象有没有被回收。
*/
public class PhantomReferences {
private static final ReferenceQueue<Sample> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) throws InterruptedException {
//创建一个虚引用指向这个对象
Sample sample = new Sample();
//如果重写了Sample的finalize方法,那么就不会放入引用队列中
PhantomReference<Sample> phantomRef = new PhantomReference<Sample>(sample,QUEUE);
sample = null;
//永远都返回null
System.out.println(phantomRef.get());
System.gc();
Thread.sleep(2000);
if(QUEUE.poll()!=null){
System.out.println("虚引用被回收了");
}
}
}