分享JVM 的四种引用方式

目录
  • 前言
  • 一、强引用
  • 二、软引用
  • 三、弱引用
  • 四、虚引用

前言

Java中提供这四种引用类型主要有两个目的:

  • 可以让程序员通过代码的方式决定某些对象的生命周期;
  • 有利于JVM进行垃圾回收

java.lang.ref包下的引用类结构图:

一、强引用

特点:GC时,永远不会被回收

是指创建一个对象并把这个对象赋给一个引用变量。

比如:

Object object = new Object();
String str = "hello"

强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。

public void fun1() {
    Object object = new Object();
    Object[] objArr = new Object[1000];
}

当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。

如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的

强引用也是导致内存泄露的主要原因

二、软引用

特点:内存不足时(自动触发GC),会被回收

如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。

SoftReference的特点是它的一个实例保存对一个Java对象的软引用, 该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。

示例:

JVM参数 -Xms10m -Xmx10m -XX:+PrintGCDetails

public static void main(String[] args) {
    Object obj = new Object();
    SoftReference<Object> softRef = new SoftReference<Object>(obj);
    System.out.println(obj);
    System.out.println(softRef.get());
    // 对象要设置为null,否则不会被回收。原因:通过设置为null让对象失去引用,方便GC
    // 备注:因为在这个main方法中(主线程),方法未结束之前,不设置为null,对象是不会失去引用的。
    obj = null;
    // 当内存不足时,会自动触发GC操作,这里就无需手动GC
    try {
        byte[] b = new byte[30 * 1024 * 1024];
    } catch (Exception e) {
        // TODO: handle exception
    } finally {
        System.out.println(obj);
        System.out.println(softRef.get());
    }
}

上述示例说明,软引用在内存不够时,通过系统的GC,回收对象了

假如有一个应用需要读取大量的本地图片:

  • 如果每次读取图片都从硬盘中读取则会严重影响性能
  • 如果一次全部加载到内存中又可能会造成内存溢出

此时使用软引用可以解决这个问题。

设计思路:用一个HashMap来保存图片的路径的相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免OOM的问题。

Map<String, SoftRefrence<Bitmap>> imageCache = new HashMap<String, SoftRefrence<Bitmap>>();

三、弱引用

特点:无论内存是否充足,只要进行GC,都会被回收

引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示

示例:

public static void main(String[] args) {
    Object obj = new Object();
    WeakReference<Object> weakRef = new WeakReference<Object>(obj);
    System.out.println(obj);            // java.lang.Object@7852e922
    System.out.println(weakRef.get());    // java.lang.Object@7852e922
    // 对象要设置为null,否则不会被回收。原因:通过设置为null让对象失去引用,方便GC
    // 备注:因为在这个main方法中(主线程),方法未结束之前,不设置为null,对象是不会失去引用的。
    obj = null;
    // 这里通过手动触发GC操作。否则内存充足的情况下很难自动触发GC
    System.gc();

    System.out.println(obj);            // null
    System.out.println(weakRef.get());    // null
}

上述示例表明,在内存充足的情况下,弱引用的对象也被回收了。

WeakHashMap的用法

public static void main(String[] args) {
    WeakHashMap<String, String> weakMap = new WeakHashMap<String, String>();
    String key = "1";
    weakMap.put(key, "test");
    System.out.println(weakMap);            // {1=test}
    System.out.println(weakMap.get(key));    // test

    key = null;
    System.gc();
    System.out.println(weakMap);            // {1=test}
    System.out.println(weakMap.get(key));    // null
}

软引用和弱引用的使用场景:mybatis中的缓存

四、虚引用

特点:如同虚设,和没有引用没什么区别

虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

示例:

public static void main(String[] args) {
    Object obj = new Object();
    ReferenceQueue<String> queue = new ReferenceQueue<String>();
    PhantomReference<String> pr = new PhantomReference<String>(obj, queue);
    System.out.println(pr.get());  // null
}

虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomRefrence的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被GC回收,用来实现比finalization机制更灵活的回收操作。

换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。

引用队列的用法

public static void main(String[] args) {
    Object obj = new Object();
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    WeakReference<Object> weakRef = new WeakReference<Object>(obj, queue);
    System.out.println(obj);             // java.lang.Object@7852e922
    System.out.println(weakRef.get());  // java.lang.Object@7852e922
    System.out.println(queue.poll());      // null

    obj = null;
    System.gc();

    System.out.println(obj);             // null
    System.out.println(weakRef.get());  // null
    System.out.println(queue.poll());     // java.lang.ref.WeakReference@4e25154f
}

到此这篇关于分享JVM 的四种引用方式的文章就介绍到这了,更多相关JVM 引用方式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • IntelliJ IDEA设置JVM运行参数的图文介绍

    目录 前言 配置方式及优先级 代码中配置 对某个Application设置 1 进入IDEA,Run–>Edit Configurations 选中要添加JVM参数的Application idea.exe.vmoption配置文件中更改 优先级 前言 之前看java虚拟机方面的知识,从理论上了解了较多的调优原理及参数,疑惑怎么才能在生产环境中设置这些虚拟机参数,今天特地学习并记录. 之前给大家介绍过几篇关于idea设置JVM运行参数的文章,喜欢的话可以点击阅读. IntelliJ IDEA设置

  • java JVM方法分派模型静态分派动态分派全面讲解

    前言 了解 行为方法分派 有利于在行为分派时时进行一些功能操作 本文全面讲解行为分派的类型:静态 & 动态行为分派,希望你们会喜欢. 目录 1. 知识储备 1.1 分派 定义:确定执行哪个方法 的过程 a. 疑问 有些读者会问,方法的执行不是取决于代码设置中的执行对象吗?为什么还要选择呢? b. 回答 若 一个对象对应于多个方法 时,就需要进行选择了 读者应该都想到了 Java中的特性:多态,即重写 & 重载.下面我会详细讲解. 分类:静态分派 & 动态分派.下面我将详细讲解. 1

  • 查看docker中运行的JVM参数问题及解决方法

    方法一.jcmd命令: 1.jps获取java的线程id 2.jcmd pidVM.flags获取 51152:-XX:CICompilerCount=3 -XX:InitialHeapSize=526385152 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=357564416 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=175112192 -XX:OldSize=351272960 -XX:+UseCompresse

  • Eclipse IDE中如何设置JVM启动参数

    目录 如何设置JVM启动参数 下面是一些设置的步骤 在Eclipse上手动设置jvm参数 典型设置 如何设置JVM启动参数 关于<深入理解Java虚拟机>里面测试OutOfMemoryError异常的部分,需要对虚拟机的启动参数进行设置 下面是一些设置的步骤 1. 右键选择项目,在弹出的菜单进行选择 2. 在弹出的Debug Configurations面板,左侧的type filter text下面选择Java Application,找到自己的项目,例如我的项目HeapOOM. 3. 在D

  • 线程崩溃不会导致 JVM 崩溃的原因解析

    目录 线程崩溃,进程一定会崩溃吗 进程是如何崩溃的-信号机制简介 为什么线程崩溃不会导致 JVM 进程崩溃 openJDK 源码解析 总结 参考文章 网上看到一个很有意思的据说是美团的面试题:为什么线程崩溃崩溃不会导致 JVM 崩溃,这个问题我看了不少回答,但都没答到根本原因,所以决定答一答,相信大家看完肯定会有收获,本文分以下几节来探讨 线程崩溃,进程一定会崩溃吗 进程是如何崩溃的-信号机制简介 为什么在 JVM 中线程崩溃不会导致 JVM 进程崩溃 openJDK 源码解析 线程崩溃,进程一

  • idea设置JVM运行参数的几种方式

    目录 方式一 方式二 方式三 对JVM运行参数进行修改是JVM性能调优的重要手段,下面介绍在应用程序开发过程中JVM参数设置的几种方式. 方式一 java程序运行时指定 -Dproperty=value 该参数通常用于设置系统级全局变量值,如配置文件路径,保证该属性在程序中任何地方都可访问.当然,也可以通过在程序中使用System.setProperty进行设置. 注意: 1.如果-Dproperty=value的value中包含空格,可以将value使用引号引起来.例如:-Dmyname="h

  • JVM中判定对象需要回收的方法

    引用计数法 每个对象上都有一个引用计数,对象每被引用一次,引用计数器就+1,对象引用被释放,引用计数器-1,直到对象的引用计数为0,对象就标识可以回收 这个可以用数据算法中的图形表示,对象A-对象B-对象C 都有引用,所以不会被回收,对象B由于没有被引用,没有路径可以达到对象B,对象B的引用计数就就是0,对象B就会被回收. 但是这个算法有明显的缺陷,对于循环引用的情况下,循环引用的对象就不会被回收.例如下图:对象A,对象B 循环引用,没有其他的对象引用A和B,则A和B 都不会被回收. root搜

  • 最新JVM垃圾回收算法详解

    目录 1.垃圾回收需要做什么 2.如何判断对象可被回收 2.1 引用计数算法 2.1.2 优点 2.1.2 缺点 2.2 可达性分析算法 2.2.1 算法思路 2.2.2 GC Roots对象(两栈两方法) 2.2.3 优点 2.2.4 缺点 3.判断对象生存还是死亡 3.1 两次标记过程 3.2 finalize()方法 4.HotSpot虚拟机中对象可达性分析的实现 4.1 枚举根节点 4.2 安全点 4.2.1 安全点是什么,为什么需要安全点 4.2.2 安全点的选定 4.2.3 如何在安

  • 分享JVM 的四种引用方式

    目录 前言 一.强引用 二.软引用 三.弱引用 四.虚引用 前言 Java中提供这四种引用类型主要有两个目的: 可以让程序员通过代码的方式决定某些对象的生命周期: 有利于JVM进行垃圾回收 java.lang.ref包下的引用类结构图: 一.强引用 特点:GC时,永远不会被回收 是指创建一个对象并把这个对象赋给一个引用变量. 比如: Object object = new Object(); String str = "hello" 强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿

  • 浅谈Java中的四种引用方式的区别

    强引用.软引用.弱引用.虚引用的概念 强引用(StrongReference) 强引用就是指在程序代码之中普遍存在的,比如下面这段代码中的object和str都是强引用: Object object = new Object(); String str = "hello"; 只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象. 比如下面这段代码: public class Main { publi

  • Java对象的四种引用方式实例分析

    本文实例讲述了Java对象的四种引用方式.分享给大家供大家参考,具体如下: 一 点睛 Java语言对对象的引用有如下四种方式 强引用:我们平时一般都是这种引用,当一个对象被一个或一个以上的引用变量所引用时,它处于可达状态,不可能被系统垃圾回收机制回收. 软引用:软引用需要通过SoftReference类来实现,当一个对象只具有软引用时,它有可能被垃圾回收机制回收.对于只有软引用的对象而言,当系统内存空间足够时,它不会被系统回收,程序也可以使用该对象,当系统内存空间不够时,系统可能回收它.软引用通

  • Java的四种引用方式

    目录 1.强引用(StrongReference) 2.软引用(SoftReference) 3.弱引用(WeakReference) 4.虚引用(PhantomReference) 5. 引用队列(ReferenceQueue) 1.强引用(StrongReference) 使用最普遍的引用. 只要引用链没有断开,强引用就不会断开.- 当内存空间不足,抛出OutOfMemoryError终止程序也不会回收具有强引用的对象. 通过将对象设置为null来弱化引用,使其被回收 Object obje

  • 详解Java的四种引用方式及其区别

    java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java对象的引用包括 强引用,软引用,弱引用,虚引用 Java中提供这四种引用类型主要有两个目的: 第一是可以让程序员通过代码的方式决定某些对象的生命周期: 第二是有利于JVM进行垃圾回收. 下面来阐述一下这四种类型引用的概念: 1.强引用 是指创建一个对象并把这个对象赋给一个引用变量. 比如: Object object =new Object(); String str ="hel

  • 浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序

    在Javascript定义一个函数一般有如下三种方式: 函数关键字(function)语句: function fnMethodName(x){alert(x);} 函数字面量(Function Literals): var fnMethodName = function(x){alert(x);} Function()构造函数: var fnMethodName = new Function('x','alert(x);') // 由Function构造函数的参数个数可变.最后一个参数写函数体

  • SpringMVC的REST风格的四种请求方式总结

    一. 在HTTP 协议里面,四个表示操作方式的动词:GET.POST.PUT.DELETE. 它们分别对应四种基本操作: 1.GET ====== 获 取资源 2.POST ======新建资源 3.PUT======= 更新资源 4.DELETE==== 删除资源 二.REST:即 Representational State Transfer.(资源)表现层状态转化.是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方便, 所以正得到越来越多网站的采用. 我们可以通过re

  • thinkPHP5.1框架中Request类四种调用方式示例

    本文实例讲述了thinkPHP5.1框架中Request类四种调用方式.分享给大家供大家参考,具体如下: 1. 传统调用 访问方式:http://127.0.0.1/demo/demo3/test?name=kk&age=22 <?php /** * Created by PhpStorm. * User: 10475 * Date: 2018/8/27 * Time: 22:59 */ namespace app\demo\controller; use think\Request; cl

  • java四种引用及在LeakCanery中应用详解

    java 四种引用 Java4种引用的级别由高到低依次为: StrongReference  >  SoftReference  >  WeakReference  >  PhantomReference 1. StrongReference String tag = new String("T"); 此处的 tag 引用就称之为强引用.而强引用有以下特征: 1. 强引用可以直接访问目标对象. 2. 强引用所指向的对象在任何时候都不会被系统回收. 3. 强引用可能导致

  • Java实现Map集合遍历的四种常见方式与用法分析

    本文实例讲述了Java实现Map集合遍历的四种常见方式与用法.分享给大家供大家参考,具体如下: ~Map集合是键值对形式存储值的,所以遍历Map集合无非就是获取键和值,根据实际需求,进行获取键和值 1. 无非就是通过map.keySet()获取到值,然后根据键获取到值 for(String s:map.keySet()){ System.out.println("key : "+s+" value : "+map.get(s)); } 2. 通过Map.Entry(

随机推荐