上章说标记算法经过根标记可达对象。是否可达(可触)这与实例的引用级别也有很大的关系。下面说几种在java中的引用级别,除了强引用其余3种均可以在java.lang.ref中找到 java
1.强引用 算法
程序中默认的引用方式。正常的赋值就是如 List<String> strs = new ArrayList()<String>() ; 那么 strs就是一个强引用。被强引用的对象为可达(可触)对象,GC没法对其回收就算内存溢出也不肯意 缓存
2.软引用 ide
被软引用的对象在GC以为内存不足时就会对其进行回收,没法知道对象在哪一时刻被销毁。这种引用用于缓存最好不过了。例: this
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("张三", "男");//这是一个强引用 SoftReference<People> PeopleSoftRef = new SoftReference<SoftRef.People>(zs);//建立了软引用 zs = null; //消除强引用 zs = PeopleSoftRef.get(); //软引用方式取得对象,这个对象有可能不存在被GC回收了 } }
3.弱引用 spa
比软件引用更加弱了,被弱引用的对象在GC一触发时就被销毁了。一样合适与缓存方式(但没有上面好,由于GC触发机率是比较高的,因此数据很容易被销毁)例: code
import java.lang.ref.WeakReference; public class WeakSoft { public static class People{ //somethig... } public static void main(String[] args) { WeakReference<People> peopleWeak = new WeakReference<WeakSoft.People>(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 ReferenceQueue<People> peopleWeakQueue = new ReferenceQueue<People>();//引用队列 public static class People{ //somethig } public static class PeopleWeakRef extends WeakReference<People>{ private String name; public PeopleWeakRef(People referent, ReferenceQueue<? super People> 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触发了一次,这时“张三”对象就被销毁了。在引用队列中能够获取了它的弱引用,但你再也找不回“张三”了。