古龙有《七种武器》,java里有四种引用。

下文主要是对 《understanding-weak-references》这一博文的重点进行翻译

强引用,strong references

StringBuffer buffer = new StringBuffer()

像上面这样的就是强引用,只要某个对象与gc root有强引用链相连,那么这个对象就不可能被gc回收掉。jvm宁可发生OOM,也不会回收这个对象。

强引用有时可能太强了

作者提出了两种场景

1. 假设我们有一个不可扩展的Widget类,现在我们想给每个Widget对象附加一个编号属性,那么我们可以这么做:额外搞一个HashMap,key是Widget对象,value是编号,通过更新与查询这个HashMap,可以实现想要的功能。

但是这个时候问题来了,如果有的Widget对象不再被使用到了(成为了垃圾),由于HashMap中保存了对所有Widget的强引用,所以GC绝对不会释放这些Widget,那么这个HashMap就会越来越大,与之关联的Widget也会越来越多,直到发生OOM。

为了解决这个问题,一个很简单的想法当然是“如果有Widget不用了,那就把它从HashMap里删掉啊”,但是如何才能知道某个Widget再不被使用了呢?总不能再弄一个引用计数系统吧。

2. 假设我们正在构建一个缓存系统,比方说把硬盘里的图片缓存到内存里,但是内存总是有限的,如果我们在内存中保存的是图片对象的强引用,那么这些对象不会在gc中被释放,这很容易就会导致内存被耗尽,然后发生OOM

弱引用  Weak References

弱引用不足以让对象在内存中强制驻留。也就是说,被弱引用修饰的对象,在gc过程中可能会被回收,你并不需要什么额外的操作。下面是使用范例:

WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);

我们可以使用weakWidget.get()方法来获取这个弱引用所指向的对象,但是由于这个对象可能已经被gc回收了,所以get到的值可能为null。

对于上面提出的第一种场景,我们可以使用系统内置的WeakHashMap来完成这一工作,WeakHashMap的特点是它的key值是WeakReference(不是value值!),而且如果WeakHashMap的某个key值被自动回收了,它所对应的value也会被自动释放。场景一的问题就这样被轻松解决了。

引用队列  Reference Queues

如果WeakReference的get方法返回null了,那么这个WeakReference所关联的对象已经被释放了,但是这个WeakReference对象本身还是存在的,它会占用空间,为了避免内存泄漏。我们需要一个机制来确保WeakReference也能被释放。

于是有了ReferenceQueue。

如果在创建WeakReference的时候,在构造函数里传入一个ReferenceQueue,那么在这个WeakReference所引用的对象被回收之后,这个WeakReference会被自动插入到ReferenceQueue里来。于是我们可以在适当的时候(比方说后台开一个定时线程)去扫描这个ReferenceQueue,然后把队列里的无用的WeakReference全部清除掉。

软引用 Soft References

软引用与弱引用极其类似,但是软引用相比之下并不急于释放所引用的对象。

弱引用不会影响gc,弱引用指向的对象只要被gc扫描到,就会被释放,但是由于gc线程的优先级很低,而且这个对象可能已经被提升到了老年代,所以这个对象还是可能存活很久。

软引用会影响gc,被软引用指向的对象只有在内存不足的时候,才会被释放掉(generally retained as long as memory is in plentiful supply)。

我个人的理解就是:软引用指向的对象可以无视young gc,只在full gc里被回收。弱引用的对象碰到young gc也会被回收。

幻引用 Phantom References

幻引用的get方法永远返回null(PhantomReference重写了父类Reference的get方法,其get方法里就一行代码:return null),也就是说一旦一个对象被放到幻引用里,就再也不可能通过这个幻引用找到它了。

它唯一的作用就是在对象被真正回收之后,放到ReferenceQueue里(因此它只有一个带有ReferenceQueue的构造方法)。

它与WeakReference的区别是:

WeakReference:一旦探测到对象只有WeakReference,就将其放入ReferenceQueue(WeakReference are enqueued as soon as the object to which they point becomes weakly reachable. This before finalization or garbage collection has actually happened.)

PhantomReference:只有在对象被真正销毁之后,才会被放入到ReferenceQueue中(PhantomReferences are enqueued only when the object is physically removed from memory.)

很奇怪,网上很多中文资料里写的都是错的。

稍微总结一下,按引用强度来划分:

强引用>软引用>弱引用>幻引用

ps: ReferenceQueue还与FinalReference有相当的关联,具体请查看参考资料中的那篇infoq的文章

参考资料

https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references

https://www.zhihu.com/question/49760047/answer/123486092

http://www.infoq.com/cn/articles/jvm-source-code-analysis-finalreference

java gc --- 四种引用的更多相关文章

  1. Java中四种引用:强、软、弱、虚引用

    这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...

  2. Java基础:Java的四种引用

    在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用.包括:强引用,软引用,弱引用,虚引用.这篇博客将详细的讲解一下这四种引用. 1. 强引用 2. 软引用 3. 弱引用 4. 虚 ...

  3. Java虚拟机(五)Java的四种引用级别

    1.前言 HotSpot采取了可达性分析算法用来判断对象是否被能被GC,无论是引用计算法还是可达性分析算法都是判断对象是否存在引用来判断对象是否存活.如果reference类型的数据中存储的数值代表的 ...

  4. Java的四种引用方式

    一.引用基本概念 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用.虚引用. 1.强引用(StrongRef ...

  5. 【转载】Java的四种引用

    在Java中,虽然不需要程序员手动去管理对象的生命周期,但是如果希望某些对象具备一定的生命周期的话(比如内存不足时JVM就会自动回收某些对象从而避免OutOfMemory的错误)就需要用到软引用和弱引 ...

  6. 转载:Java的四种引用方式

    原文:https://www.cnblogs.com/huajiezh/p/5835618.html Java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指 ...

  7. [转载] Java的四种引用关系

    目录 1 强引用 (Final Reference) 2 软引用 (Soft Reference) 2.1 案例1: 软引用的垃圾回收 2.2 案例2: 软引用缓存的使用 2.3 软引用的应用场景 3 ...

  8. JAVA的四种引用,强弱软虚用到的场景

    1.强引用 最常用的引用类型,如Object object = new Object(),只要强引用存在,GC必定 不回收,即使当前内存空间不足,jAVA虚拟机宁愿抛出OutofMemoryError ...

  9. Java的四种引用,强弱软虚,用到的场景

    众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方便,程序不用再像使用c那样操心内存),但同时也是它的缺点(不够灵活).为了解决内存操作不灵活这个问题,可以采用软引用等方法. 在J ...

随机推荐

  1. Jack Straws POJ - 1127 (简单几何计算 + 并查集)

    In the game of Jack Straws, a number of plastic or wooden "straws" are dumped on the table ...

  2. Broken robot CodeForces - 24D (概率DP)

    You received as a gift a very clever robot walking on a rectangular board. Unfortunately, you unders ...

  3. Codeforces Round #435 (Div. 2) B (二分图) C(构造)

    B. Mahmoud and Ehab and the bipartiteness time limit per test 2 seconds memory limit per test 256 me ...

  4. 遗传算法 | C++版GA_TSP

    嗯哼,时隔半年,再次有时间整理关于组合优化问题——旅行商问题(Traveling Salesman Problem, TSP),这次采用的是经典遗传算法(Genetic Algorithm, GA)进 ...

  5. Python基础闯关失败总结

    对列表进行创建切片增删改查 对列表进行创建 L1 = []  # 定义L1 为一个空列表 List() #创建List 空列表 对列表进行查询 L2 = ['a','b','c','d','a','e ...

  6. Cakephp在Controller中显示sql语句

    Cakephp在Controller中查询语句一般是: $this->Model->find(); 那么这条语句对应的sql语句是什么呢? 可以通过下面方法显示: 1. $dbo = Co ...

  7. 创建数据收集器集(DSC)

    TechNet 库 Windows Server Windows Server 2008 R2 und Windows Server 2008 按类别提供的 Windows Server 内容 按类别 ...

  8. leetcode 【 Search in Rotated Sorted Array II 】python 实现

    题目: 与上一道题几乎相同:不同之处在于array中允许有重复元素:但题目要求也简单了,只要返回true or false http://www.cnblogs.com/xbf9xbf/p/42545 ...

  9. ogre3D学习基础5 -- 阴影与动画

    五.阴影 阴影是渲染一个真实场景的重要组成部分,它可以给场景中的物体提供更加真实的感觉,同时还可以帮助用户更好的了解对象间的空间关系. 启用阴影: 缺省情况下,阴影是关闭的,开启方式如下: 1.建立场 ...

  10. Python+Selenium练习篇之15-在浏览器中新开一个tab

    本文介绍如selenium方法打开一个新的tab,我们知道在浏览器里,我们按住 ctrl+ t 就可以新打开一个tab.所以我们学习如何利用webdriver中send_key 的方法去触发ctrl+ ...