强引用
这是最常见的引用关系,变量o对 new object()这个对象(下称对象xx)的进行引用,o持有对象的强引用,宁愿内存溢出也不清除强引用的内存
Object obj = new Object();//o 持有这个新new出来对象xx的强引用
//不需要之后 将obj置为null,这样对象xx就没有引用了,变为不可达,会在下次gc的时候回收掉
obj = null;//help GC
obj置为null的情况下,如果想继续对对象xx进行引用处理,只能再次new一个出来,在这种场景下,jdk1.2后出了一个java.lang.ref包,加强了对对象的生命周期的控制,同时也可以作为java的内置缓存,使得在引用不可达的情况下 仍可以被使用
软引用SoftReference
丢到SoftReference中就是软引用,内存快溢出了就把软引用的干掉
@Test
public void test1() throws Exception {
//软引用
Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
SoftReference<Object> softReference = new SoftReference<Object>(obj,queue);
System.out.println("原始obj:" + obj);//java.lang.Object@32a1bec0
obj = null;//删除强引用
System.gc();//手动gc
Thread.currentThread().sleep(1000);//确保gc执行
System.out.println("null obj:" + obj);
// queue.poll();//软弱虚引用gc后对象就会放入queue 而poll操作则是拿出队列的头对象 即取得并删除
System.out.println("软引用 get :" + softReference.get());//内存足够 不会gc java.lang.Object@32a1bec0
//弱引用
Object obj2 = new Object();
WeakReference<Object> weakReference = new WeakReference<Object>(obj2,queue);
obj2 = null;
System.gc();
Thread.currentThread().sleep(1000);
System.out.println("弱引用 get :" + weakReference.get());//内存足够 也会被gc null 对象放入queue }
弱引用WeakReference
一旦执行GC就会清除
虚引用
使用很少
当多种引用关系并存的时候以那个为准呢?
强引用>软引用>弱引用>虚引用 当然是以强的为主
比如前面代码的若是obj不置为null,那即便obj有软/弱引用,那对象也是强引用
GC交互原理
个人推测,gc底层算法中会对各种不同引用采用不对的算法,对不同GCroot采用策略对待
对于gc与queue的交互,即便看了Reference/ReferenceQueue的源码,也还是不明白GC时为何就会将数据丢入queue中,Reference中的守护线程只是改变状态而已也是GC底层算法
WeakHashMap
看名字就知道和弱引用有很大关系,发现很多框架使用这个map
其内部的Entry维护了一个
/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
//创建了弱引用 以key的弱引用 即key变为null时 会被回收掉 和value无关
this.value = value;
this.hash = hash;
xt = next;
}}
*
/**
* Expunges stale entries from the table.get/size等使用map时就会调用这个方法
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
//queue.poll()从queue取出并删除x,然后对比map中key 并从map中删除这个entry 即自动回收
}