上章说标记算法通过根标记可达对象。是否可达(可触)这与实例的引用级别也有很大的关系。下面说几种在java中的引用级别,除了强引用其他3种都可以在java.lang.ref中找到
1.强引用
程序中默认的引用方式。正常的赋值就是如 List<String> strs = new ArrayList()<String>() ; 那么 strs就是一个强引用。被强引用的对象为可达(可触)对象,GC无法对其回收就算内存溢出也不愿意
2.软引用
被软引用的对象在GC觉得内存不足时就会对其进行回收,无法知道对象在哪一时刻被销毁。这种引用用于缓存最好不过了。例:
import java.lang.ref.SoftReference;public class SoftRef { public static class People{ private String name; private String gender; public People(String name, String gender) { this.name = name; this.gender = gender; } //get/set .... } public static void main(String[] args) { People zs = new People("张三", "男");//这是一个强引用 SoftReferencePeopleSoftRef = new SoftReference (zs);//创建了软引用 zs = null; //消除强引用 zs = PeopleSoftRef.get(); //软引用方式取得对象,这个对象有可能不存在被GC回收了 } }
3.弱引用
比软件引用更加弱了,被弱引用的对象在GC一触发时就被销毁了。同样合适与缓存方式(但没有上面好,因为GC触发机率是比较高的,所以数据很容易被销毁)例:
import java.lang.ref.WeakReference;public class WeakSoft { public static class People{ //somethig... } public static void main(String[] args) { WeakReferencepeopleWeak = new WeakReference (new People("张三", "男")); People zs = peopleWeak.get(); //弱引用方式取得对象,这个对象很有可能已经被销毁了 }}
4.虚引用(了解)
这个是引用类型中最弱的,持有虚引用的对象有跟没有一样。如上当你试图用get()取出,总会失败。是一个不可达对象,虚引用必须和引用队列一起使用。它的作用仅仅在于跟踪回收过程(就是它被GC回收,在队列中让你知道一下就ok了)。
--------------------------------------------------------------------
扩展 软引用、弱引用、虚引用与它们的引用队列
这三种引用随时会被GC回收,但回收后它会被丢到引用队列中,在队列中你可以找到它们的身影,但仅用来跟踪查看而已例:
java -Xmx10M -XX:+PrintGC WeakSoft
import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;public class WeakSoft { public static ReferenceQueuepeopleWeakQueue = new ReferenceQueue ();//引用队列 public static class People{ //somethig } public static class PeopleWeakRef extends WeakReference { private String name; public PeopleWeakRef(People referent, ReferenceQueue q) { super(referent, q); this.name = referent.getName(); } //get/set } public static class TraceRefQueue implements Runnable{ @Override public void run() { while (true) { PeopleWeakRef peopleRef = null; try { peopleRef = (PeopleWeakRef) peopleWeakQueue.remove(); } catch (InterruptedException e) { throw new RuntimeException(e); } if(peopleRef!=null){ System.out.println(peopleRef.getName()+" 被移除了!"); System.out.println(peopleRef.get()); } } } } public static void main(String[] args) throws InterruptedException { Thread traceRefQueueThread = new Thread(new TraceRefQueue());//启动一个守护进程,监听GC移除动作 traceRefQueueThread.setDaemon(true); traceRefQueueThread.start(); PeopleWeakRef peopleWeakRef = new PeopleWeakRef(new People("张三", "男"),peopleWeakQueue); //让GC触发 byte[] memory = new byte[3*1024*1024]; memory = new byte[2*1024*1024]; memory = new byte[2*1024*1024]; }}
最后结果:
[GC 5794K->5632K(9728K), 0.0078318 secs]
张三 被移除了! null输出说明:看到GC触发了一次,这时“张三”对象就被销毁了。在引用队列中可以获取了它的弱引用,但你再也找不回“张三”了。