面试官考察Java引用会问到强引用、弱引用、软引用、虚引用,具体有什么区别?本篇单独来详解 @mikechen

Java引用

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

强引用

强引用是最普遍的引用,一般把一个对象赋给一个引用变量,这个引用变量就是强引用。

比如:

  1. // 强引用
  2. MikeChen mikechen=new MikeChen();

在一个方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(MikeChen)保存在Java堆中。

如果一个对象具有强引用,垃圾回收器不会回收该对象,当内存空间不足时,JVM 宁愿抛出 OutOfMemoryError异常。

如果强引用对象不使用时,需要弱化从而使GC能够回收,如下:

  1. //帮助垃圾收集器回收此对象
  2. mikechen=null;

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

举例:

  1. package com.mikechen.java.refenence;
  2.  
  3. /**
  4. * 强引用举例
  5. *
  6. * @author mikechen
  7. */
  8. public class StrongRefenenceDemo {
  9.  
  10. public static void main(String[] args) {
  11. Object o1 = new Object();
  12. Object o2 = o1;
  13. o1 = null;
  14. System.gc();
  15. System.out.println(o1); //null
  16. System.out.println(o2); //java.lang.Object@2503dbd3
  17. }
  18. }

StrongRefenenceDemo 中尽管 o1已经被回收,但是 o2 强引用 o1,一直存在,所以不会被GC回收。

软引用

软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference 类来实现。

比如:

  1. String str=new String("abc"); // 强引用
  2. SoftReference<String> softRef=new SoftReference<String>(str); // 软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。

先通过一个例子来了解一下软引用:

  1. /**
  2. * 弱引用举例
  3. *
  4. * @author mikechen
  5. */
  6. Object obj = new Object();
  7. SoftReference softRef = new SoftReference<Object>(obj);//删除强引用
  8. obj = null;//调用gc
  9.  
  10. // 对象依然存在
  11. System.gc();System.out.println("gc之后的值:" + softRef.get());

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

  1. ReferenceQueue<Object> queue = new ReferenceQueue<>();
  2. Object obj = new Object();
  3. SoftReference softRef = new SoftReference<Object>(obj,queue);//删除强引用
  4. obj = null;//调用gc
  5. System.gc();
  6. System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在
  7. //申请较大内存使内存空间使用率达到阈值,强迫gc
  8. byte[] bytes = new byte[100 * 1024 * 1024];//如果obj被回收,则软引用会进入引用队列
  9. Reference<?> reference = queue.remove();if (reference != null){
  10. System.out.println("对象已被回收: "+ reference.get()); // 对象为null
  11. }

软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。

我们看下 Mybatis 缓存类 SoftCache 用到的软引用:

  1. public Object getObject(Object key) {
  2. Object result = null;
  3. SoftReference<Object> softReference = (SoftReference)this.delegate.getObject(key);
  4. if (softReference != null) {
  5. result = softReference.get();
  6. if (result == null) {
  7. this.delegate.removeObject(key);
  8. } else {
  9. synchronized(this.hardLinksToAvoidGarbageCollection) {
  10. this.hardLinksToAvoidGarbageCollection.addFirst(result);
  11. if (this.hardLinksToAvoidGarbageCollection.size() > this.numberOfHardLinks) {
  12. this.hardLinksToAvoidGarbageCollection.removeLast();
  13. }
  14. }
  15. }
  16. }
  17. return result;}

注意:软引用对象是在jvm内存不够的时候才会被回收,我们调用System.gc()方法只是起通知作用,JVM什么时候扫描回收对象是JVM自己的状态决定的,就算扫描到软引用对象也不一定会回收它,只有内存不够的时候才会回收。

弱引用

弱引用的使用和软引用类似,只是关键字变成了 WeakReference:

  1. MikeChen mikechen = new MikeChen();
  2. WeakReference<MikeChen> wr = new WeakReference<MikeChen>(mikechen );

弱引用的特点是不管内存是否足够,只要发生 GC,都会被回收。

举例说明:

  1. public class WeakHashMapDemo {
  2.  
  3. public static void main(String[] args) throws InterruptedException {
  4. myHashMap();
  5. myWeakHashMap();
  6. }
  7.  
  8. public static void myHashMap() {
  9. HashMap<String, String> map = new HashMap<String, String>();
  10. String key = new String("k1");
  11. String value = "v1";
  12. map.put(key, value);
  13. System.out.println(map);
  14.  
  15. key = null;
  16. System.gc();
  17.  
  18. System.out.println(map);
  19. }
  20.  
  21. public static void myWeakHashMap() throws InterruptedException {
  22. WeakHashMap<String, String> map = new WeakHashMap<String, String>();
  23. //String key = "weak";
  24. // 刚开始写成了上边的代码
  25. //思考一下,写成上边那样会怎么样? 那可不是引用了
  26. String key = new String("weak");
  27. String value = "map";
  28. map.put(key, value);
  29. System.out.println(map);
  30. //去掉强引用
  31. key = null;
  32. System.gc();
  33. Thread.sleep(1000);
  34. System.out.println(map);
  35. }}

弱引用的应用

WeakHashMap

  1. public class WeakHashMapDemo {
  2.  
  3. public static void main(String[] args) throws InterruptedException {
  4. myHashMap();
  5. myWeakHashMap();
  6. }
  7.  
  8. public static void myHashMap() {
  9. HashMap<String, String> map = new HashMap<String, String>();
  10. String key = new String("k1");
  11. String value = "v1";
  12. map.put(key, value);
  13. System.out.println(map);
  14.  
  15. key = null;
  16. System.gc();
  17.  
  18. System.out.println(map);
  19. }
  20.  
  21. public static void myWeakHashMap() throws InterruptedException {
  22. WeakHashMap<String, String> map = new WeakHashMap<String, String>();
  23. //String key = "weak";
  24. // 刚开始写成了上边的代码
  25. //思考一下,写成上边那样会怎么样? 那可不是引用了
  26. String key = new String("weak");
  27. String value = "map";
  28. map.put(key, value);
  29. System.out.println(map);
  30. //去掉强引用
  31. key = null;
  32. System.gc();
  33. Thread.sleep(1000);
  34. System.out.println(map);
  35. }}

当key只有弱引用时,GC发现后会自动清理键和值,作为简单的缓存表解决方案。

ThreadLocal

  1. static class ThreadLocalMap {
  2.  
  3. static class Entry extends WeakReference<ThreadLocal<?>> {
  4. Object value;
  5.  
  6. Entry(ThreadLocal<?> k, Object v) {
  7. super(k);
  8. value = v;
  9. }
  10. }
  11. //......}

ThreadLocal.ThreadLocalMap.Entry 继承了弱引用,key为当前线程实例,和WeakHashMap基本相同。

虚引用

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

虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。

虚引用需要java.lang.ref.PhantomReference 来实现:

  1. A a = new A();
  2. ReferenceQueue<A> rq = new ReferenceQueue<A>();
  3. PhantomReference<A> prA = new PhantomReference<A>(a, rq);

虚引用主要用来跟踪对象被垃圾回收器回收的活动。

虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

Java引用总结

java4种引用的级别由高到低依次为:强引用 > 软引用 > 弱引用 > 虚引用。

以上

作者简介

陈睿|mikechen,10年+大厂架构经验,《BAT架构技术500期》系列文章作者,分享十余年BAT架构经验以及面试心得!

阅读mikechen的互联网架构更多技术文章合集

Java并发|JVM|MySQL|Spring|Redis|分布式|高并发|架构师

Java四大引用详解:强引用、软引用、弱引用、虚引用的更多相关文章

  1. Java对象的强、软、弱和虚引用详解

    1.对象的强.软.弱和虚引用 转自:http://zhangjunhd.blog.51cto.com/113473/53092/ 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...

  2. 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用

    垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...

  3. Java:对象的强、软、弱、虚引用

    转自: http://zhangjunhd.blog.51cto.com/113473/53092 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...

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

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

  5. Java:对象的强、软、弱和虚引用

    1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...

  6. java基础知识再学习--集合框架-对象的强、软、弱和虚引用

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://zhangjunhd.blog.51cto.com/113473/53092 本文 ...

  7. Java对象的强、软、弱和虚引用原理+结合ReferenceQueue对象构造Java对象的高速缓存器

    //转 http://blog.csdn.net/lyfi01/article/details/6415726 1.Java对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变 ...

  8. Java:对象的强、软、弱和虚引用[转]

    原文链接:http://zhangjunhd.blog.51cto.com/113473/53092/ 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  9. Java对象的强、软、弱和虚引用+ReferenceQueue

    Java对象的强.软.弱和虚引用+ReferenceQueue 一.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足 ...

  10. Java:对象的强、软、弱和虚引用的区别

    1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...

随机推荐

  1. c# 简单的滑动图片验证

    普通的验证码对用户使用体验不友好,出现了滑动图片验证的验证方式,用户只要按住滑块完成图片的拼接即可通过验证(这是最简单的方式,滑动轨迹,数据分析,滑行速度 什么的暂没考虑) 主要的实现思路: 1.先从 ...

  2. [NOI2011]阿狸打字机

    题意:一开始是个空串s,有三种操作:(1.末尾加一个字符 2.末尾减一个字符 3.存储该字符串) 思路: 一开始在trie树上动态加点很好处理,3操作的时候记录一下此时trie树上的pos,同时记录d ...

  3. TornadoFx实现侧边栏菜单效果

    原文地址:TornadoFx实现侧边栏菜单效果 - Stars-One的杂货小窝 之前年前研究的东西,给蓝奏批量下载器重构了页面,实现了侧边栏菜单的效果,稍微总结下把 效果 实现 首先,要说明的是,总 ...

  4. flask实现python方法转换服务

    一.flask安装 pip install flask 二.flask简介: flask是一个web框架,可以通过提供的装饰器@server.route()将普通函数转换为服务 flask是一个web ...

  5. 内网穿透frp教程 windows远程桌面连接

    鉴于ngrok不是特别好用 昨天又发现frp这个神器 在管理端还有图形界面十分友好 话不多说开始 准备工作 1.一个域名 2.一台服务器 一.域名与服务器 域名和服务器直接买就好咯 价格不高 一定要在 ...

  6. 轻松上手Fluentd,结合 Rainbond 插件市场,日志收集更快捷

    以往有篇文章介绍 EFK(Kibana + ElasticSearch + Filebeat)的插件日志收集.Filebeat 插件用于转发和集中日志数据,并将它们转发到 Elasticsearch ...

  7. RPA应用场景-银行回单查询

    场景概述银行回单查询 所涉系统名称银行网银 人工操作(时间/次) 5 分钟 所涉人工数量 4 操作频率不定时 场景流程 1.收到外派业务员申请查询收入银行回单的邮件: 2.依据邮件中提供的客户信息进入 ...

  8. 告别单调,Django后台主页改造 - 使用AdminLTE组件

    前言 之前我做了个Django的项目,为了让管理后台更加美观,我对Django(应该说是SimpleUI的)默认的Admin后台主页进行改造,具体可以看这篇文章:项目完成 - 基于Django3.x版 ...

  9. Pytorch从0开始实现YOLO V3指南 part3——实现网络前向传播

    本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...

  10. 虚拟机安装Centos7.5详细教程

    VMware15.5虚拟机安装CentOS7.5详细教程   (前言)软件下载   需要VMware15.5软件和密匙的小伙伴可以从此地址下载:https://pan.baidu.com/s/1A8H ...