设为首页 - 加入收藏 安康站长网 (http://www.0915zz.com)- 国内知名站长资讯网站,提供最新最全的站长资讯,创业经验,网站建设等!
热搜: 手机 2019 苹果 如何
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

Java 中的四种引用

发布时间:2019-10-26 20:08 所属栏目:[优化] 来源:健程之道
导读:之前我们提到过 GC,但当 Java 中引用的对象越来越多,会导致内存空间不足,最终会产生错误 OutOfMemoryError,并让应用程序终止。那为什么 GC 在此时不能多收集一些对象呢?这就和今天说的引用类型有关了。 首先,从 JDK1.2 开始,对象的引用被划分为4种级

之前我们提到过 GC,但当 Java 中引用的对象越来越多,会导致内存空间不足,最终会产生错误 OutOfMemoryError,并让应用程序终止。那为什么 GC 在此时不能多收集一些对象呢?这就和今天说的引用类型有关了。

首先,从 JDK1.2 开始,对象的引用被划分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

强引用

强引用(Strong Reference)是使用最普遍的引用。如果一个对象具有强引用,那么它永远不会被 GC。例如:

  1. Object?strongReference?=?new?Object();?

当内存空间不足时,JVM 宁愿抛出OutOfMemoryError,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

如果强引用对象不使用时,需要弱化从而可以被 GC,例如ArrayList中的clear()方法:

  1. /**?
  2. *?Removes?all?of?the?elements?from?this?list.?The?list?will?
  3. *?be?empty?after?this?call?returns.?
  4. */?
  5. public?void?clear()?{?
  6. modCount++;?
  7. ?
  8. //?clear?to?let?GC?do?its?work?
  9. for?(int?i?=?0;?i?
  10. elementData[i]?=?null;?
  11. ?
  12. size?=?0;?
  13. }?

显式地设置强引用对象为null,或让其超出对象的生命周期范围,则垃圾回收器认为该对象不存在引用,就会回收这个对象。具体什么时候收集这要取决于具体的垃圾回收器。

软引用

如果一个对象只具有软引用(Soft Reference),当内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。让我们来看一个例子具体了解一下:

  1. String?str?=?new?String("abc");?
  2. SoftReference?softReference?=?new?SoftReference<>(str);?
  3. String?result?=?softReference.get();?

让我们来看一下get():

  1. public?T?get()?{?
  2. T?o?=?super.get();?
  3. //?timestamp代表上一次软引用上一次被使用的时间(初始化、get())?
  4. //?clock代表上一次GC的时间?
  5. if?(o?!=?null?&&?this.timestamp?!=?clock)?
  6. this.timestamp?=?clock;?
  7. return?o;?
  8. }?

因此,软引用在被垃圾回收时,也遵循LRU法则,优先回收最近最少被使用的对象进行回收。

软引用的使用场景多是内存敏感的高速缓存。具体来说,就是我们希望将数据存放到缓存中,这样可以快速进行读取。但是,当 JVM 中内存不够用时,我们又不希望缓存数据会占用到 JVM 的内存。例如配合ReferenceQueue,如果软引用所引用对象被垃圾回收,JVM 就会把这个软引用加入到与之关联的引用队列中:

  1. ReferenceQueue?referenceQueue?=?new?ReferenceQueue<>();?
  2. String?str?=?new?String("abc");?
  3. SoftReference?softReference?=?new?SoftReference<>(str,?referenceQueue);?
  4. ?
  5. str?=?null;?
  6. //?Notify?GC?
  7. System.gc();?
  8. ?
  9. System.out.println(softReference.get());?//?abc?
  10. ?
  11. Reference?reference?=?referenceQueue.poll();?
  12. System.out.println(reference);?//null?

但是需要注意的是,如果使用软引用缓存,有可能导致Full GC增多。

弱引用

如果一个对象只具有弱引用(Weak Reference),其生命周期相比于软引用更加短暂。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会对它进行回收。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。其使用为:

  1. String?str?=?new?String("abc");?
  2. WeakReference?weakReference?=?new?WeakReference<>(str);?
  3. str?=?weakReference.get();?

讲到弱引用,就不得不提到WeakHashMap。和HashMap相比,当我们给 JVM 分配的内存不足的时候,HashMap 宁可抛出 OutOfMemoryError 异常,也不会回收其相应的没有被引用的对象,而 WeakHashMap 则会回收存储在其中但有被引用的对象。

WeakHashMap 通过将一些没有被引用的键的值赋值为 null ,这样的话就会告知GC去回收这些存储的值了。假如我们特地传入 key 为 null 的键,WeakHashMap 会将键设置为特殊的 Oject,源码为:

  1. public?V?put(K?key,?V?value)?{?
  2. //?key会被重新赋值?
  3. Object?k?=?maskNull(key);?
  4. int?h?=?hash(k);?
  5. Entry[]?tab?=?getTable();?
  6. int?i?=?indexFor(h,?tab.length);?
  7. ?
  8. for?(Entry?e?=?tab[i];?e?!=?null;?ee?=?e.next)?{?
  9. if?(h?==?e.hash?&&?eq(k,?e.get()))?{?
  10. V?oldValue?=?e.value;?
  11. if?(value?!=?oldValue)?
  12. e.value?=?value;?
  13. return?oldValue;?
  14. }?
  15. }?
  16. ?
  17. modCount++;?
  18. Entry?e?=?tab[i];?
  19. tab[i]?=?new?Entry<>(k,?value,?queue,?h,?e);?
  20. if?(++size?>=?threshold)?
  21. resize(tab.length?*?2);?
  22. return?null;?
  23. }?
  24. ?
  25. /**?
  26. *?Value?representing?null?keys?inside?tables.?
  27. *?特殊的key?
  28. */?
  29. private?static?final?Object?NULL_KEY?=?new?Object();?
  30. ?
  31. /**?
  32. *?Use?NULL_KEY?for?key?if?it?is?null.?
  33. */?
  34. private?static?Object?maskNull(Object?key)?{?
  35. return?(key?==?null)???NULL_KEY?:?key;?
  36. }?

虚引用

虚引用(PhantomReference),顾名思义,就是形同虚设。与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。 虚引用与软引用和弱引用的一个区别在于:

【免责声明】本站内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

网友评论
推荐文章