整体架构

强引用

强引用是默认支持,当内存不足的时候,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. G. Yash And Trees 线段树 + dfs序 + bitset

    这个是要用bitset 一个大整数的二进制 学习推荐博客 这个题目大意就是:给你n,m 还有一个序列,还有一个一棵树,有一种操作一种询问 操作是给你一个节点 把这个节点及其子节点都加上x 询问是 给你 ...

  2. 架构设计 | 分布式系统调度,Zookeeper集群化管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.框架简介 1.基础简介 Zookeeper基于观察者模式设计的组件,主要应用于分布式系统架构中的,统一命名服务.统一配置管理.统一集群管理 ...

  3. vue 如何实现 Input 输入框模糊查询方法

    原理:原生js的indexOf() 方法,该方法将从头到尾地检索数组,看它是否含有对应的元素.开始检索的位置在数组 start 处或数组的开头(没有指定 start 参数时).如果找到一个 item, ...

  4. static RMQ

    RMQ问题:对于长度为N的序列,询问区间[L,R]中的最值 RMQ(Range Minimum/Maximum Query),即区间最值查询. 常见解法: 1.朴素搜索 2.线段树 3.DP 4.神奇 ...

  5. 关于日常操作中sql的性能

    最近接手了一个项目.使用的数据库是sql server,但是遇到一些关于日期的查询的时候,查询结果非常慢.看了下别人的sql //sql = sql + " and CONVERT(nvar ...

  6. 微信浏览器中禁止下拉出现网页由xxx.xxxxx.com提供,QQ浏览器X5内核提供技术支持这个

    直接上代码 window.onload = function(){ document.body.addEventListener('touchmove', function (e) { e.preve ...

  7. 【转载】文件上传那些事儿,文件ajax无刷上传

    导语 正好新人导师让我看看能否把产品目前使用的FileUploader从老的组件库分离出来的,自己也查阅了相关的各种资料,对文件上传的这些事有了更进一步的了解.把这些知识点总结一下,供自己日后回顾,也 ...

  8. Java -> 构造器(构造方法)

    构造方法 我们对封装已经有了基本的了解,接下来我们来看一个新的问题,依然以Person为例,由于Person中的属性都被private了,外界无法直接访问属性,必须对外提供相应的set和get方法.当 ...

  9. 题解 洛谷P2959 【[USACO09OCT]悠闲漫步The Leisurely Stroll】

    原题:洛谷P2959 不得不说这道题的图有点吓人,但实际上很多都没有用 通过题上说的“三岔路口”(对于每一个节点有三条连接,其中一条连接父节点,另外两条连接子节点)和数据,可以那些乱七八糟的路和牧场看 ...

  10. at命令用法详解

    在linux系统中你可能已经发现了为什么系统常常会自动的进行一些任务?这些任务到底是谁在支配他们工作的? 在linux系统如果你想要让自己设计的备份程序可以自动在某个时间点开始在系统底下运行,而不需要 ...