深入理解Java中的引用(二)——强软弱虚引用

深入理解Java中的引用(二)——强软弱虚引用

在上一篇文章中介绍了Java的Reference类,本篇文章介绍他的四个子类:强引用、软引用、弱引用、虚引用。

强引用(StrongReference)

强引用是我们在代码中最普通的引用。示例代码如下:

Object o = new Object();   //  强引用  

在JVM的GC算法中,如果一个对象具有强引用,那么JVM宁可抛出Out of Memory错误,垃圾回收器也不会去回收这个对象。
当在代码里显示的写o = null,或者该对象的引用作用域是在一个函数里,代码如下,当线程调用完test,就会退出方法栈,引用不存在,垃圾回收器才会在某个时刻回收Object对象。

public void test(){
    Object o = new Object();   //  强引用 
}

软引用(SoftReference)

如果一个对象有一个软引用,那么在内存足够的情况下,该对象就不会被垃圾回收器回收。网上有很多资料说软引用只会在内存空间不够用的情况下对象才会被回收。 那么什么时候才是内存不够用呢?

首先看一下SoftReference类的源码可以看到有两个字段。这两个字段的作用已经标注,这与JVM GC有什么关系呢?

    /**
     * 记录最近一次被GC的时间。
     */
    static private long clock;

    /**
     * 每次调用get方法的时候更新
     * 记录当前Reference最近一次被访问的时间
     */
    private long timestamp;

一起看一下HotSpot的源码,对于软引用的回收策略见下面should_clear_reference函数。

// The oop passed in is the SoftReference object, and not
// the object the SoftReference points to.
bool LRUMaxHeapPolicy::should_clear_reference(oop p,
                                             jlong timestamp_clock) {
  jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);
  assert(interval >= 0, "Sanity check");

  // The interval will be zero if the ref was accessed since the last scavenge/gc.
  if(interval <= _max_interval) {
    return false;
  }

  return true;
}

上述代码中interval表示当前引用存活了多久。他的值就是对应上述java代码中的clocktimestamp相减。interval_max_interval比较,如果大于 _max_interval,那么就和弱引用一样处理,如果小于就当做强引用处理。_max_interval的赋值函数如下:

// Capture state (of-the-VM) information needed to evaluate the policy
void LRUMaxHeapPolicy::setup() {
  size_t max_heap = MaxHeapSize;
  max_heap -= Universe::get_heap_used_at_last_gc();
  max_heap /= M;

  _max_interval = max_heap * SoftRefLRUPolicyMSPerMB;
  assert(_max_interval >= 0,"Sanity check");
}

通过源码可见首先是max_heap减去上次GC之后剩余堆大小,如果上次GC之后还有很多剩余空间,说明内存空间不够用了,那么max_heap的值就越小,相应_max_interval也越小,软引用就越可能被回收。

软引用的一个作用是实现内存敏感的高速缓存。比如浏览器的后退按钮,
(1)如果网页浏览结束就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建。
(2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出。
通过软引用可以解决该问题

 Browser prev = new Browser();               // 获取页面进行浏览  
 SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用         
 if(sr.get()!=null){   
    rev = (Browser) sr.get();           // 还没有被回收器回收,直接获取  
 }else{ 
     prev = new Browser();               // 由于内存吃紧,所以对软引用的对象回收了  
     sr = new SoftReference(prev);       // 重新构建  
}  

弱引用(WeakReference)

只具有弱引用的对象生命周期更短。当垃圾回收器发现了只有弱引用的对象时候,无论内存空间是否足够,都会被GC回收当你偶尔需要引用某个对象,随时能获取该对象,但是不想介入该对象的生命周期的时候,就可以使用弱引用, 因为弱引用不会对对象的垃圾回收判断产生附加的影响。
当弱引用绑定的对象被垃圾回收的时候,JVM会把这个弱引用加入到相关联的ReferenceQueue中。
这里抛出两个问题:
(1)弱引用什么时候会被加入到ReferenceQueue中,由什么决定的呢?
(2)如果绑定的对象GC之后存活了下来,弱引用怎么知道这个对象的新地址呢?
第一种情况,GC扫描到只存在弱引用的时候就会把它放到链表里。还有第二种情况:一个对象既有强引用又有弱引用的情况
下面通过图片来解释上面两个问题:

image.png

上图表示C同时存在两个引用:强引用A和弱引用B。

第一种情况:GC先扫描到A
这种情况下GC同时会扫描到C,A和C都会搬到Survivor区。然后扫描到B,发现B引用的C搬到到了新的Survivor,这个时候就把B也搬到Survivor,并把C的新地址更新到B,结果如下:


image.png

第二种情况:GC先扫描到B
GC还是会先把B放到ReferenceQueue中,由于C还是存活的,所以B会被搬到Survivor中。然后扫描到A,A和C都会搬到Survivor中,GC结束的时候B所指向的对象就不对了,如下图所示


image.png

该情况下会重新遍历ReferenceQueue,发现绑定的对象依然存活,C‘ 的指针是指向C的,于是就把B再指向C就可以了,同时因为C依然存活,把B从ReferenceQueue中移除。新的地址空间如下图所示:


image.png

具体过程可以查看海纳知乎专栏。

虚引用(PhantomReference)

虚引用不会对对象的垃圾回收有任何附加影响,他与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。查看他的构造方法可以看到必须与一个ReferenceQueue绑定,而且他的get方法返回的一直是null

public T get() {
        return null;
    }
    
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

虚引用主要用在跟踪对象垃圾回收的状态。具体应用会在在下一节讲到DirectByteBuffer 与ThreadLoal回收的时候详细分析。

总结

关于强引用、软引用、弱引用与虚引用在垃圾回收时的区别可以用下图表示:


image.png

下图总结了四种引用在其他方面的区别:


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

推荐阅读更多精彩内容