整体架构

强引用

强引用是默认支持,当内存不足的时候,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会回收对象。

强引用是最常见的普通对象引用,只要还有强引用指向对象,对象就存活,垃圾回收器不会处理存活对象。一般把一个对象赋给一个引用变量,这个引用变量就是强引用。当一个对象被强引用变量所引用,它就处于可达状态,是不会被垃圾回收的,即使之后都不会再用到了,也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。

关于Java内存泄漏的详细内容,可以参考这篇博客:https://blog.csdn.net/m0_38110132/article/details/81986334

对于一个普通对象,如果没有其他引用关系,只要超过了引用的作用域或者显式地将相应的强引用赋值为null,一般认为就是可以被垃圾回收了。(具体的回收时机看垃圾回收策略)

下例中,b就是强引用。

     public static void main(String[] args) {
Object a = new Object();
Object b = a;
a = null;
System.out.println(b);//java.lang.Object@4554617c
}

软引用

软引用是一种相对强引用弱化了一些的引用,用java.lang.ref.SoftReference实现,可以让对象豁免一些垃圾收集。当系统内存充足的时候,不会被回收;当系统内存不足的时候,会被回收。

软引用一般用于对内存敏感的程序中,比如高速缓存。

 import java.lang.ref.SoftReference;

 public class SoftReferenceDemo {
public static void main(String[] args) {
Object a = new Object();
SoftReference<Object> softReference = new SoftReference<>(a);//软引用
//a和软引用指向同一个对象
System.out.println(a);//java.lang.Object@4554617c
System.out.println(softReference.get());//java.lang.Object@4554617c //内存够用,软引用不会被回收
a = null;
System.gc();//内存够用不会自动gc,手动唤醒gc
System.out.println(a);//null
System.out.println(softReference.get());//java.lang.Object@4554617c //内存不够用时
try{
//配置Xms和Xmx为5MB
byte[] bytes = new byte[1024*1024*30];//设置30MB超内存
}catch (Throwable e){
e.printStackTrace();
}finally {
System.out.println(a);//null
System.out.println(softReference.get());//null
}
}
}

使用场景

一个应用需要读取大量的本地图片,如果每次读取都从硬盘读取会严重影响性能,如果一次性全部加载到内存,内存可能会溢出。

可以使用软引用解决这个问题,使用一个HashMap来保存图片路径和图片对象管理的软引用之间的映射关系,内存不足时,JVM会自动回收缓存图片对象的占用空间,有效地避免了OOM(Out Of Memory)问题。

Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>

弱引用

弱引用需要用java.lang.ref.WeakReference实现,它比软引用的生存期更短,对于弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否够,都会回收该对象的占用内存。

 import java.lang.ref.WeakReference;

 public class SoftReferenceDemo {
public static void main(String[] args) {
Object a = new Object();
WeakReference<Object> softReference = new WeakReference<>(a);//软引用
//a和弱引用指向同一个对象
System.out.println(a);//java.lang.Object@4554617c
System.out.println(softReference.get());//java.lang.Object@4554617c //内存够用,弱引用也会被回收
a = null;
System.gc();//内存够用不会自动gc,手动唤醒gc
System.out.println(a);//null
System.out.println(softReference.get());//null
}
}

关于WeakHashMap

     public static void weakHashMapTest() {
Integer key = new Integer(1);
String value = "李四";
Map<Integer,String> weakHashMap = new WeakHashMap();
weakHashMap.put(key, value);
System.out.println(weakHashMap);//{1=李四}
key = null;
System.gc();
System.out.println(weakHashMap);//{}
} public static void hashMapTest() {
HashMap<Integer,String> map = new HashMap<>();
Integer key = 1;
String value = "张三";
map.put(key,value);
System.out.println(map);//{1=张三}
key = null;
System.gc();
System.out.println(map);//{1=张三}
}

在HashMap中,键被置为null,唤醒gc后,不会垃圾回收键为null的键值对。但是在WeakHashMap中,键被置为null,唤醒gc后,键为null的键值对会被回收。

虚引用

虚引用要通过java.lang.ref.PhantomReference类来实现,虚引用不会决定对象的生命周期,如果一个对象只有虚引用,就相当于没有引用,在任何时候都可能会被垃圾回收器回收。它不能单独使用也不能访问对象,虚引用必须和引用队列联合使用。

虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供一种确保对象被finalize以后,做某些事情的机制。

PhantomReference的get方法总是返回null,因此无法访问对应的引用对象,设置虚引用关联唯一的目的是在对象被收集器回收的时候收到一个系统通知,或者后续添加进一步的处理。Java允许使用finalize()方法在垃圾回收器将对象从内存中清理出去之前做一些必要的清理工作。【例如实现一个监控对象的通知机制】

引用队列

WeakReference和ReferenceQueue的联合使用效果:

     public static void weakReferenceTest() {
Object a = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> weakReference = new WeakReference<>(a,queue);
System.out.println(a);//java.lang.Object@4554617c
System.out.println(weakReference.get());//java.lang.Object@4554617c
System.out.println(queue.poll());//null
System.out.println("-------------------");
a = null;
System.gc();
System.out.println(a);//null
System.out.println(weakReference.get());//null
//虚引用在回收之前被加入到了引用队列中
System.out.println(queue.poll());//java.lang.ref.WeakReference@74a14482
}

PhantomReference和ReferenceQueue的联合使用效果:

     public static void phantomReferenceTest() {
Object a = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(a,queue);
System.out.println(a);//java.lang.Object@4554617c
System.out.println(phantomReference.get());//null
System.out.println(queue.poll());//null
System.out.println("-------------------");
a = null;
System.gc();
System.out.println(a);//null
System.out.println(phantomReference.get());//null
//引用在回收之前被加入到了引用队列中
System.out.println(queue.poll());//java.lang.ref.WeakReference@74a14482
}

总结

强引用:不回收。

软引用:内存不够就回收。

弱引用:一定回收。

虚引用:一定回收,get出来就是null,引用形同虚设,主要和引用队列联合使用,在finalize之前会被放到引用队列中。

与根对象没有引用关系的:引用不可达,一定回收。

【JVM】如何理解强引用、软引用、弱引用、虚引用?的更多相关文章

  1. jvm系列 (四) ---强、软、弱、虚引用

    java引用 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 我的博客目录 为什么将引用分为不同的强度 因为我们需要实现这样一种情 ...

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

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

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

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

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

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

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

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

  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对象的强、软、弱和虚引用

    本文介绍Java对象的强.软.弱和虚引用的概念.应用及其在UML中的表示. 1.Java对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象 ...

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

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

随机推荐

  1. 从0开始学自定义View -1

    PS:好久没有写博客了,之前的东西有所忘记,百度一下竟然查到了自己的写过的博客,访问量还可以,一开始的写博客的初衷是把自己不会的记录下来,现在没想到也有博友会关注我,这就给了我动力,工作之余把零零碎碎 ...

  2. qt creator源码全方面分析(4-2)

    目录 global头文件 global.h xx.h global头文件 插件的本质就是动态链接库,对于库,需要导出符号,供用户导入使用.在qt creator的源码中,存在固定的导入导出模式. gl ...

  3. golang关键字select的三个例子, time.After模拟socket/心跳超时

    golang关键字select的三个例子, time.After模拟socket/心跳超时   例子1 select会随机选择一个可执行的case   // 这个例子主要说明select是随机选择一个 ...

  4. spring中bean的常用属性

    一.scop scope用来配置bean对象是否是单例模式.单例模式是java的二十三种设置模式之一,指在这个项目运行过程中一 个类的对象只会实例化一次.一般,工厂类的对象都是单例模式.非单例模式叫多 ...

  5. DHCP报文(1)

    DHCP报文 1.地址申请类型(4步工作原理,常考) (1)此题是典型的四步工作原理,在其配置过程中由于没有分配IP地址,用的是广播形式,所以其4中报文类型的目的IP地址均为255.255.255.2 ...

  6. 【FPGA篇章三】FPGA常用语句:Verilog基本语法要素

    欢迎大家关注我的微信公众账号,支持程序媛写出更多优秀的文章 Verilog中总共有十九种数据类型,我们先介绍四个最基本的数据类型,他们是: reg型.wire型.integer型.parameter型 ...

  7. 【Spark】使用java语言开发spark程序

    目录 步骤 一.创建maven工程,导入jar包 二.开发代码 步骤 一.创建maven工程,导入jar包 <properties> <scala.version>2.11.8 ...

  8. STM32 Cube之旅-尝试新的开发方式

    尝试使用Cube进行一些开发学习,这里对此做一个梗概,先有一个全面的了解. 文章目录 Cube全家桶 CubeMX CubeIDE CubeProg 结语 Cube全家桶 曾几何时,ST刚推出Cube ...

  9. Redis的几种集群方式分析

    一 单机版 分析: 无论多少用户,都访问这一台服务器 .服务器一旦挂了,所有用户都无法访问.风险很大,一般不会有人使用. 二 主从模式(master/slaver) 分析: 主从模式中, 无论多少用户 ...

  10. XShell 评估到期

    刚刚打开XShell弹出”评估到期“,点击确定后自动打开中文官网,得购买后才能使用. 当初下载的时候没留意到会有这一天.. 手头拮据的朋友可以通过下面方法绕过: 删除XShell. 到英文官网下载页找 ...