Java强软弱虚四大引用

2024-01-21 12:04
文章标签 java 引用 四大 软弱

本文主要是介绍Java强软弱虚四大引用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、强引用
  • 二、软引用
  • 三、弱引用
  • 四、虚引用


提示:以下是本篇文章正文内容,下面案例可供参考

一、强引用

在Java中,强引用(Strong Reference)是最常见的引用类型。当我们创建一个对象并将其赋值给一个变量时,实际上就是创建了一个强引用。这意味着只要这个引用变量还存在,垃圾回收器就不会回收它所引用的对象。(除非等于null)

简单来说日常使用的大部分都是强引用,即使OOM也不回收,所以往往是导致内存泄露的元凶

代码如下(示例):

public class Test {public static void main(String[] args) throws Throwable {/*** 虚拟机配置选项* VM Options :-XX:+PrintGCDetails -Xms10m -Xmx10m* -XX:+PrintGCDetails:打印 GC 的详细信息* -Xms10m:设置初始化堆空间大小为 10m* -Xmx10m:设置最大堆空间大小为 10m*/// 强引用byte[] bytes = new byte[4 * 1024 * 1024];// 调用 GCSystem.gc();}
}

输出结果(如下):

可以看出 bytes 并没有存储任何数据,仅仅是开辟空间,但是 GC 后仍然存在

在这里插入图片描述

在这里插入图片描述


二、软引用

在Java中,软引用(SoftReference)是一种特殊类型的引用,它比强引用弱,但比弱引用强。当系统内存不足时,即 JVM 空间即将耗尽,垃圾回收器会优先清理那些只被软引用关联的对象。如果一个对象只剩下软引用,那么在内存充足的情况下,该对象不会被回收;但在内存不足时,这个软引用指向的对象会被垃圾回收器回收以释放内存。
软引用通常用于实现内存敏感的缓存,例如图片缓存。当系统内存紧张时,这些缓存可以被自动清除,从而避免了 OutOfMemoryError 异常的发生,同时,在内存资源相对充足时,又能保持缓存的功能,提高程序性能。

简单来说,就是内存不足是才回收

代码如下(示例):

public class Test {public static void main(String[] args) throws Throwable {/*** 虚拟机配置选项* VM Options :-XX:+PrintGCDetails -Xms10m -Xmx10m* -XX:+PrintGCDetails:打印 GC 的详细信息* -Xms10m:设置初始化堆空间大小为 10m* -Xmx10m:设置最大堆空间大小为 10m*/// 软引用Map<String, SoftReference<byte[]>> map = new HashMap<>();// 最大 10m 的堆空间肯定装不 24m 的数组,所以 JVM 会自动 GC 回收map.put("bytes1", new SoftReference<>(new byte[6 * 1024 * 1024]));map.put("bytes2", new SoftReference<>(new byte[6 * 1024 * 1024]));map.put("bytes3", new SoftReference<>(new byte[6 * 1024 * 1024]));// 强引用数组,无法回收byte[] bytes2 = new byte[6 * 1024 * 1024];}
}

输出结果(如下):

可以看出JVM多次调用 GC 回收软引用
在这里插入图片描述


三、弱引用

在Java中,弱引用(WeakReference)是一种特殊的引用类型,它代表的对象可被垃圾回收器在任何时候回收,即使该对象仍然有弱引用存在。相比于强引用(普通引用),只要强引用还在,垃圾回收器就不会回收该对象;而软引用和弱引用都允许在内存不足时回收其引用的对象,但软引用会在系统内存尚充足的情况下尽可能保留对象,而弱引用则不考虑当前内存状况。
弱引用的典型使用场景是在缓存或者映射关系中,当主要持有对象的强引用消失后,即使还有其他地方通过弱引用关联到这个对象,也依然会被垃圾回收器视为无用对象并进行回收。

简单来说,就是只要GC就会回收

代码如下(示例):

public class Test {public static void main(String[] args) {/*** 虚拟机配置选项* VM Options :-XX:+PrintGCDetails* -XX:+PrintGCDetails:打印 GC 的详细信息*/// 弱引用// 开辟一个很小的数组WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[10]);// GC 前System.out.printf(Arrays.toString(weakReference.get()));System.out.println();System.gc();// GC 后System.out.printf(Arrays.toString(weakReference.get()));System.out.println();}
}

输出结果(如下):

可以看出这个很小的数组在GC后直接没了,即使空间充足

在这里插入图片描述


四、虚引用

虚引用,顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。
虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。
PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作。换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

源代码如下:

public class PhantomReference<T> extends Reference<T> {/*** Returns this reference object's referent.  Because the referent of a* phantom reference is always inaccessible, this method always returns* <code>null</code>.** @return  <code>null</code>*/public T get() {return null;}/*** Creates a new phantom reference that refers to the given object and* is registered with the given queue.** <p> It is possible to create a phantom reference with a <tt>null</tt>* queue, but such a reference is completely useless: Its <tt>get</tt>* method will always return null and, since it does not have a queue, it* will never be enqueued.** @param referent the object the new phantom reference will refer to* @param q the queue with which the reference is to be registered,*          or <tt>null</tt> if registration is not required*/public PhantomReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}}

简单来说就是虚引用不存储任何东西,且必须配合引用队列使用,它唯一的作用就是监控绑定的对象是否被回收

代码如下(示例):


public class Test {public static void main(String[] args) {// 虚引用// 作用:监控对象的回收情况// 要监控的对象Object o1 = new Object();// 引用队列ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();// 虚引用绑定对象和引用队列PhantomReference<Object> phantomReference = new PhantomReference<>(o1, referenceQueue);// 回收前的被监控的对象System.out.println("回收前的被监控的对象: " + o1);// 虚引用地址System.out.println("虚引用地址: " + phantomReference);// 源码可知,总是返回 nullSystem.out.println("虚引用的返回值: " + phantomReference.get());// 所以队列也返回 nullSystem.out.println("引用队列的返回值: " + referenceQueue.poll());System.out.println("====================");// 置空监控的对象o1 = null;// 回收对象System.gc();// 监控的对象System.out.println("回收后的对象: " +o1);// 虚引用地址System.out.println( "虚引用地址: " + phantomReference);// 源码可知,总是返回 nullSystem.out.println("虚引用的返回值: " + phantomReference.get());// 重点!!!!!// 引用队列中存储了虚引用,说明该对象被回收了// 这就是虚引用的唯一目的,即 gc 后将自身加入到引用队列System.out.println("引用队列的返回值: " + referenceQueue.poll());}
}

输出结果(如下):

在这里插入图片描述


这篇关于Java强软弱虚四大引用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/629481

相关文章

Spring Boot整合Redis注解实现增删改查功能(Redis注解使用)

《SpringBoot整合Redis注解实现增删改查功能(Redis注解使用)》文章介绍了如何使用SpringBoot整合Redis注解实现增删改查功能,包括配置、实体类、Repository、Se... 目录配置Redis连接定义实体类创建Repository接口增删改查操作示例插入数据查询数据删除数据更

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题

Java使用Swing生成一个最大公约数计算器

《Java使用Swing生成一个最大公约数计算器》这篇文章主要为大家详细介绍了Java使用Swing生成一个最大公约数计算器的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下... 目录第一步:利用欧几里得算法计算最大公约数欧几里得算法的证明情形 1:b=0情形 2:b>0完成相关代码第二步:加

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

Java Map排序如何按照值按照键排序

《JavaMap排序如何按照值按照键排序》该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实... 目录一、先理清 3 种 Map 的默认排序行为二、按「键」排序的实现方式1. 方式 1:用 TreeM

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,