Java弱引用的理解与使用

WeakReference

前言

看到篇帖子, 国外一个技术面试官在面试senior java developer的时候, 问到一个weak reference相关的问题. 他没有期望有人能够完整解释清楚weak reference是什么, 怎么用, 只是期望有人能够提到这个concept和java的GC相关. 很可惜的是, 20多个拥有5年以上java开发经验的面试者中, 只有两人知道weak reference的存在, 而其中只有一人实际用到过他. 无疑, 在interviewer眼中, 对于weak reference的理解和应用在面试中给了这一个interviewee相当多的加分.  所以, 将我对于这个技术的理解和使用总结在这篇推文里, 希望读者和自己通过读和写这篇推文, 能够在以后的工作和面试中获得加分.

在Java里, 当一个对象o被创建时, 它被放在Heap里. 当GC运行的时候, 如果发现没有任何引用指向o, o就会被回收以腾出内存空间.

或者换句话说:

一个对象被回收, 必须满足两个条件:

1.没有任何引用指向它 

2.GC被运行.

在现实情况写代码的时候, 我们往往通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收 (可以用java -verbose:gc来观察gc的行为)

Object c = new Car();c=null;

But:

手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的.  对于简单的情况, 手动置空是不需要程序员来做的, 因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了.

但是, 也有特殊例外. 当使用cache的时候, 由于cache的对象正是程序运行需要的, 那么只要程序正在运行, cache中的引用就不会被GC给(或者说, cache中的reference拥有了和主程序一样的life cycle). 那么随着cache中的reference越来越多, GC无法回收的object也越来越多, 无法被自动回收. 当这些object需要被回收时, 回收这些object的任务只有交给程序编写者了. 然而这却违背了GC的本质(自动回收可以回收的objects).

所以, java中引入了weak reference. 相对于前面举例中的strong reference:

Object c = new Car(); //只要c还指向car object, car object就不会被回收
  • 当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收. weak reference的语法是:

WeakReference weakCar = new WeakReference(Car)(car);
  • 当要获得weak reference引用的object时, 首先需要判断它是否已经被回收:

weakCar.get(); //如果此方法为空, 那么说明weakCar指向的对象已经被回收了.

下面来看一个例子:

//Car类package weakreference;/** * @author wison */public class Car {  private double price;  private String colour;    public Car(double price, String colour){    this.price = price;    this.colour = colour;  }    public double getPrice() {    return price;  }  public void setPrice(double price) {    this.price = price;  }  public String getColour() {    return colour;  }  public void setColour(String colour) {    this.colour = colour;  }    public String toString(){    return colour +"car costs $"+price;  }  }
package weakreference;import java.lang.ref.WeakReference;/** * @author wison */public class TestWeakReference {    public static void main(String[] args) {    //看这块代码    Car car = new Car(22000,"silver");    WeakReference weakCar = new WeakReference(car);    int i=0;    while(true){      if(weakCar.get()!=null){        i++;        System.out.println("Object is alive for "+i+" loops - "+weakCar);      }else{        System.out.println("Object has been collected.");        break;      }    }  }}

在上例中, 程序运行一段时间后, 程序打印出"Object has been collected." 说明, weak reference指向的对象的被回收了.

值得注意的一点 :

即使有 car 引用指向对象, 且 car 是一个strong reference, weak reference weakCar指向的对象仍然被回收了. 这是因为java的编译器在发现进入while循环之后, car 已经没有被使用了, 所以进行了优化(将其置空?). 当把TestWeakReference.java修改为:

package weakreference;import java.lang.ref.WeakReference;/** * @author wison */public class TestWeakReference {  public static void main(String[] args) {        Car car = new Car(22000,"silver");    WeakReference weakCar = new WeakReference(car);        int i=0;        while(true){      System.out.println("here is the strong reference 'car' "+car);      if(weakCar.get()!=null){        i++;        System.out.println("Object is alive for "+i+" loops - "+weakCar);      }else{        System.out.println("Object has been collected.");        break;      }    }  }}

weak reference指向的object就不会被回收了. 因为还有一个strong reference car 指向它.

注意: WeakReference的一个特点是它何时被回收是不可确定的, 因为这是由GC运行的不确定性所确定的. 所以, 一般用weak reference引用的对象是有价值被cache, 而且很容易被重新被构建, 且很消耗内存的对象.

推文

后记

-ReferenceQueue

weak reference指向的对象被回收后, weak reference本身其实也就没有用了. java提供了一个ReferenceQueue来保存这些所指向的对象已经被回收的reference. 用法是在定义WeakReference的时候将一个ReferenceQueue的对象作为参数传入构造函数.

其他类型的references

-SoftReference

soft reference和weak reference一样,

但被GC回收的时候需要多一个条件: 当系统内存不足时(GC是如何判定系统内存不足? 是否有参数可以配置这个threshold?), soft reference指向的object才会被回收. 正因为有这个特性, soft reference比weak reference更加适合做cache objects的reference. 因为它可以尽可能的retain cached objects, 减少重建他们所需的时间和消耗.

自知之明是最难得的知识,

最灵繁的人也看不见自己的背脊。

——《C++团队》

使用java理解程序逻辑 第十二章_Java弱引用的理解与使用相关推荐

  1. 使用java理解程序逻辑 第十二章_Java多线程中锁的理解与使用(二)

    博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注.一起学习,一起成长. 独享锁/共享锁 独享锁是指该锁一次只能被一个线程所 ...

  2. 微信小程序(第二十二章)- 表单数据提交

    微信小程序(第二十二章)- 表单数据提交 问题 实现步骤 问题 什么时候(怎样)提交数据? 当点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 ...

  3. vilatile 深入理解java虚拟机_《深入理解Java虚拟机》笔记 第十二章 volatile变量

    当一个变量定义成volatile之后,它将具备两种特性: 1.第一是保证此变量对所有线程的可见性,这里的"可见性"是指当一条线程修改了这个变量的值,新值对于其它线程是可以立即得知的 ...

  4. Java并行程序基础(十二)

    2019独角兽企业重金招聘Python工程师标准>>> 无锁 对于并发控制而言,锁是一种悲观策略.它总是假设每一次的临界区操作会产生冲突,因此,必须对每次操作都小心翼翼.如果多个线程 ...

  5. java类库支持_第十二章:开发支持类库

    UUID类 UUID(since 1.5   java.util.UUID)是一种生成无重复字符串的程序类,这种程序类的主要功能是根据时间戳实现一个自动的无重复的字符串定义.所谓的无重复只出现概率很低 ...

  6. 奋斗吧,程序员——第二十二章 事了拂衣去,深藏身与名

    穿过黝黑的通道,时不时看到有人从走廊两边的房间风风火火地跑出来,差点和我撞个满怀. 外包公司确实是程序员里最苦逼的一群,这些人上厕所都是用跑的. "索尼租下这幢大楼,专门供给第三方公司员工使 ...

  7. book1复习 使用java理解程序逻辑

    book1复习 使用java理解程序逻辑 第一章 初识Java 开发步骤 编写源代码 编译源文件 运行 基本命令 输出内容:1,输出换行. 2,输出不换行 输入内容:获得键盘的输入 注释 单行注释 多 ...

  8. 题库明细 使用java理解程序逻辑

    题库明细 使用java理解程序逻辑 初识java 变量.数据类型和运算符 选择结构(一) 选择结构(二) 循环结构(一) 循环结构(二) 数组 循环结构进阶 类和对象 类的无参方法 带参数的方法 字符 ...

  9. 【JAVA SE】第十二章 流(Stream)、IO流和文件(File)

    第十二章 流(Stream).IO和文件(File) 文章目录 第十二章 流(Stream).IO和文件(File) 一.流(Stream) 1.什么是流 2.流的分类 二.IO流 1.字节输入流(I ...

最新文章

  1. python小数输出01_python:格式化输出(上)
  2. C#代码创建3D模型
  3. Android组件之BroadCast简单实践
  4. java B2B2C Springboot电子商城系统
  5. linux php oauth安装,Linux php 扩展安装 mongo ,redis ,soap,imap,pdo_mysql,oauth
  6. 重庆邮电大学计算机科学与技术培养方案,重庆邮电大学计算机科学与技术学院.doc...
  7. hexo评论_【前端简历加分】hexo框架搭建个人博客站点,手把手教学
  8. 不用背景图片,只用css代码实现面包屑样式
  9. Mysql_mysql多个TimeStamp设置
  10. python网络爬虫学习笔记(八):XPath的使用
  11. C语言的本质(2)——二进制、八进制、十六进制与十进制
  12. ELKF(Elasticsearch+Logstash+ Kibana+ Filebeat) 部署
  13. ScreenFlow 录制Mac电脑声音
  14. 图像同时对比度、空间分辨率、幅度分辨率的实现
  15. linux capability
  16. 不用U盘从linux重装win系统,不用U盘和光盘安装win7旗舰版系统
  17. 计算机网络之(4):DNS
  18. Unity 2D 摄像机平滑跟随
  19. 交换机模拟配置软件_GNS3 for mac(网络模拟工具)
  20. python爬虫网易云音乐最热评论并分析_网易云音乐热门评论api分析

热门文章

  1. android 动态移动xy,android – 如何使用AChartEngine动态线图和X轴自动平移(滚动)?...
  2. s matlab toolbox,Matlab Robotic Toolbox工具箱学习笔记(一 )
  3. 数学之美 系列八-- 贾里尼克的故事和现代语言处理
  4. YOLOv1 《You Only Look Once》论文笔记
  5. 2017年10月05日普及组 负进制
  6. jquery实现截取pc图片_jquery实现图片裁剪思路及实现
  7. xxljob 配置文件_SpringBoot整合Xxl-Job的完整步骤记录
  8. Android实战——第三方服务之Bmob后端云的推送服务的集成和使用(三)
  9. python3 logging模块
  10. 关于Authorware的十二种使用技巧