一、强引用
强引用是我们日常写代码最常遇到的引用类型,如:Object obj = new Object(),obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 垃圾回收器不会回收这类对象,即使JVM内存空间不足,JVM宁愿抛出OutOfMemoryError,也不会通过回收具有强引用的对象来解决内存空间不足的问题,只有当超过了引用的作用域或者显示的将强引用赋null,该对象才会被垃圾回收器回收,具体的回收时机要看垃圾收集策略。
创建一个java对象
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("没有更多的引用指向"+name+"对象,对象即将被清理");
}
}
为了更好的观察,这里我重写了Object对象的finalize()方法,该方法会被垃圾收集器回调,调用时机是当垃圾收集器确定已经没有更多的引用指向这个对象时。
public static void main(String[] args) throws InterruptedException {
//user1会超过作用域
{
User user1=new User("u1");
}
//user2显示的将强引用赋null
User user2=new User("u2");
user2=null;
User user3=new User("u3");
System.gc();
Thread.sleep(5000);
}
打印:
没有更多的引用指向u2对象,对象即将被清理
没有更多的引用指向u1对象,对象即将被清理
二、软引用(SoftReference)
软引用比强引用弱化很多,只有软引用的对象会在JVM内存空间不足时,或者说在JVM 抛出 OutOfMemoryError 之前,清理掉软引用指向的对象,来达到释放内存的目的。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉一些缓存,这样就保证了使用缓存的同时,内存不会耗尽。比如安卓的LruCache缓存类。
public static void main(String[] args) throws InterruptedException {
User user=new User("张三");
SoftReference<User> soft=new SoftReference<User>(user);
user=null;
System.gc();
/*
* soft.get() @return The object to which this reference refers,
* or null if this reference object has been cleared
*/
if(soft.get()==null) {
System.out.println("软引用对象已经被清理,此时没有引用指向User对象");
}else {
System.out.println("name:"+soft.get().getName());
}
}
结果:
name:张三
可以看到即使我们运行垃圾收集器对象依然可以soft.get()获取到,因为这里系统内存依然充足当然不会回收这个对象了,只有软引用的对象只有在系统内存不足时才会被回收。
软引用可以和一个引用队列联合使用,通常如果软引用所引用的对象被垃圾收集器回收,JVM就会把这个软引用添加到引用队列中。我们可以调用ReferenceQueue的poll()方法来检查其中是否有Reference对象存在,若有代表该软引用指向的对象已经被回收,否则,返回null。
ReferenceQueue queue=new ReferenceQueue();
SoftReference<User> soft=new SoftReference<User>(user,queue);
user=null;
if(queue.poll()!=null) {
System.out.println("User对象被回收");
}
三、弱引用(WeakReference)
弱引用的生命周期比软引用还短,可以 理解为比软引用更“弱”的引用,当垃圾收集器只要扫描到只具有弱引用的对象,不管内存是否充足,都会回收该对象,因此弱引用不能让对象豁免被垃圾收集器回收的可能,但是需要注意的是垃圾收集器的线程优先级很低,因此对象还是有可能会保留一段时间不被回收的。弱引用同样也是实现缓存策略的一种选择。
//弱引用
User user=new User("张三");
WeakReference<User> weak=new WeakReference<User>(user);
user=null;
//System.gc();
if(weak.get()==null) {
System.out.println("弱引用对象已经被清理,此时没有引用指向User对象");
}else {
System.out.println("name:"+weak.get().getName());
}
如上代码,虽然只要垃圾收集器扫描到具有弱引用的对象就会回收它,但是由于垃圾收集器的线程优先级较低,因此对象是有可能保留一段时间的。执行结果如下:
name:张三
如果我们将System.gc()这句代码的注释取消,执行结果如下:
弱引用对象已经被清理,此时没有引用指向User对象
没有更多的引用指向张三对象,对象即将被清理
因为这里我们人为的运行垃圾收集器。
弱引用同样可以和引用队列(ReferenceQueue)联用。如果弱引用所引用的对象被回收,JVM就会把这个弱引用添加到引用队列中。
四、虚引用(PhantomReference)
虚引用也被称为幻象引用,一个对象如果只有虚引用的话,就相当于没有任何引用一样,需要注意的是通过虚引用的get方法是获取不到对象的。虚引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制,我们可以通过虚引用来观察对象的创建和销毁。虚引用必须和引用队列一起使用,当垃圾收集器将要回收一个只有虚引用的对象时,就会把这个虚引用添加到引用队列,我们可以通过观察引用队列是否添加了虚引用来判断一个对象是否即将被回收。
User user=new User("张三",12);
ReferenceQueue queue=new ReferenceQueue();
PhantomReference<User> phantomRef=new PhantomReference<User>(user,queue);
user=null;