Java引用

四种引用:强引用,软引用,弱引用,虚引用
为什么要引入不同引用的概念?之前由于内存小,对象就两种状态,要么被引用,要么被清除,随着内存的扩大,java充实了对象的状态,于是就有了这四种引用;

强引用

你的代码中绝大多数都是强引用。
如果一个对象,GC root可达,GC清理宁可抛出OOM异常终止程序,也不会清理掉它;

软引用

用于描述那些不是必需的对象,但由于内存充足可保留,适合用作缓存。那么GC什么时候能够清理掉软引用呢?

public class SoftReference<T> extends Reference<T> {

    /**
     * Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /**
     * Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }


    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }


    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

注意这两个变量clock 和 timestamp;
在JVM发生GC时,也会更新clock的值,意味着clock会记录上次GC发生的时间点;
另一个变量timestamp,在软引用初始化时,会被初始化成clock,同时在get方法被调用时,也会更新timestamp的值;
所以如果一个SoftReference长时间没有被调用(即get方法没被调用)那么clock 和 timestamp之间会形成差值;
首先当GC时,会先检查该SoftReference所引用的对象是否还存活,即GC root是否可达;若不可达就会尝试回收引用对象,这里有几种回收策略,如LRUCurrentHeapPolicy;该种策略下,会对clock 和 timestamp差值与某个值进行比较,这个值的大小与上次GC后剩余空间大小正相关,也就是对空间剩余空间越大,对象存活越长;

弱引用

WeakReference:相对于软引用,它的生命周期更短,当发生GC时,如果扫描到一个对象只有弱引用,不管当前内存是否足够,都会对它进行回收。
还记得ThreadLocal里对它的的引用吗?ThreadLocalMap里的Entry继承的就是WeakReference,它将对ThreadLocal对象的引用设为弱引用,在检测到key为null之后会对entry进行清理再重新rehash,如getEntry,set,remove方法;所以我们一般这样使用:

private final static ThreadLocal memory = new ThreadLocal();

延长它的生命周期,并在需要的时候主动调用remove清理,防止OOM。
为什么使用弱引用?如上我们将memory = null,表示要删除存储的数据,则此时ThreadLocal对象只剩弱可达性,那么GC启动后,Entry就会被清理;如果是强引用,那么ThreadLocal对象仍是可达的就不会被清理,容易引发OOM;在WeakHashMap中也是此设计;

虚引用

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }

PhantomReference它的get方法返回null;
虚引用的使用场景很窄,在JDK中,目前只知道在申请堆外内存时有它的身影。
申请堆外内存时,在JVM堆中会创建一个对应的Cleaner对象,这个Cleaner类继承了PhantomReference,当DirectByteBuffer对象被回收时,可以执行对应的Cleaner对象的clean方法,做一些后续工作,这里是释放之前申请的堆外内存。
虚引用存在的唯一作用就是当它指向的对象被回收后,虚引用本身会被加入到引用队列中,用作记录它指向的对象已被回收。

Reference

除了强引用外,其他几种都继承自Reference;

    private T referent;         /* Treated specially by GC */

    volatile ReferenceQueue<? super T> queue;

    Reference next;

    transient private Reference<T> discovered;

    private static Reference<Object> pending = null;
  1. referent:指所要引用的对象
  2. queue:ReferenceQueue队列,存放Reference
  3. next: Reference进队列呈链表结构
  4. discovered:被JVM使用,表示下一个要被处理的Reference对象
  5. pending:被JVM使用,当前被处理的Reference对象;

Reference里有个ReferenceHandler线程,优先级极高,负责轮询检查pending值,不为空则放入队列;我们可以利用这点对要清初的对象进行些操作,如下例:

    public static void main(String[] args) {
        final ReferenceQueue queue = new ReferenceQueue();
        new Thread(){
            @Override
            public void run() {
                try {
                    Reference reference = queue.remove();
                    System.out.println(reference + "被回收");
                } catch (InterruptedException e) {

                }
            }
        }.start();
        Object ob = new Object();
        Reference root = new WeakReference(ob, queue);
        System.out.println(root);
        ob = null;
        System.gc();
    }

gc()启动后,弱引用对象ob要被清除于是被赋予到penging上,ReferenceHandler线程会将它放入到我们的queue当中,我们从queue取出进行打印操作;

参考

Java软引用究竟什么时候被回收
如何有效的避免OOM,温故Java中的引用
十分钟理解Java中的弱引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 来源:朱小厮 链接:http://blog.csdn.net/u013256816/article/details...
    会点代码的大叔阅读 341评论 0 1
  • 概述 java.lang.ref 类库包含一组类,为垃圾回收提供了更大的灵活性。 java.lang.ref 有三...
    bing__chen阅读 413评论 0 2
  • 强引用 ( Strong Reference ) 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝...
    tomas家的小拨浪鼓阅读 2,804评论 1 4
  • 很多人说要我去找一份工作,并非我不愿意,而是实在走不开。爸妈总是有事,家里实际白天只有我自己,我走了,今天就不用开...
    呼吸的鲸鱼阅读 321评论 0 0
  • 毕竟,谁也不知道什么时候会下雨,未雨绸缪总没错。 大学毕业五周年聚会上,所有人都聊嗨了。走狗屎运的在高谈阔论,点儿...
    疯狂的黑色幽默阅读 745评论 7 14