古龙有《七种武器》,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. stark组件(1):动态生成URL

    项目启动时自动生成URL 效果图: 知识点: Django启动前通过apps下的ready方法执行一个可以生成URL的py文件 include函数主要返回有三个元素的一个元组.第一个是url配置(ur ...

  2. [BZOJ1010]玩具装箱toy(斜率优化)

    Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1... ...

  3. [BZOJ2947]促销(Splay)

    Description Great Bytelandish的超级市场网络请你编写一个程序模拟促销商品的成本费用(simulating costs of the promotionbeing prepa ...

  4. mysql-不恰当的update语句使用主键和索引导致mysql死锁

    背景知识:MySQL有三种锁的级别:页级.表级.行级. MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):BDB存储引擎采用的是页面锁(page-level ...

  5. C语言用一维数组打印杨辉三角(原:无意中想到)

    本贴地址 ] = { }; a[] = , a[] = ; int i, j,m; ; i <= ; i++) //2-11 输出10行 { ; j > ; j--) //关键在这句,倒着 ...

  6. 使用 Dom4j 将 XML 转换为 MAP

    本文为转载:http://blog.sina.com.cn/s/blog_6145ed810100z164.html  原文地址. 自己仅作备忘录方便查找留了一份. 这是解析Xml 的辅助类 pack ...

  7. android 内存说明

    MemoryInfo的Field如下 dalvikPrivateDirty: The private dirty pages used by dalvik. dalvikPss :The propor ...

  8. Spring框架配置beans.xml

    Spring学习笔记(一) 一.Spring 框架 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 ...

  9. PAT1026

    要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock()函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间.这个时间单位是clock tick,即“时 ...

  10. Weixin API -- 微信js接口

    今天在开发项目的时候,由于需要在微信中实现分享功能(分享成功后实现页面跳转并记录).问度娘,找了很久,终于找到一个不错的方法.收藏起来以后备用,也希望对大家有所帮助! 在github的地址:https ...