Java对象的引用类型

转载自 Java对象的引用类型

Java对象的引用类型有强引用,软引用,弱引用,虚引用和FinalReference,提供这几种引用类型的主要目的:

1.程序员可以通过不同的引用方式决定某些对象的生命周期;
2.利用JVM的垃圾回收机制,对象可达性分析,进行不同策略的垃圾回收;
3.合理的利用软,弱,虚引用可以避免内存溢出等风险。

     下面来详细谈谈这几种类型引用,首先需要了解一下对象的可达性,java对象不同生命周期,可达性的状态也是不一样,具体分为强可达,软可达,和弱可达,幻象可达和不可达(不可达基本上可以直接回收了),这些可达性状态基本上对应着对象引用的类型关系 ,jvm依赖对象可达性来进行垃圾回收的。

 

1.强引用

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

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

     强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

2.引用

     说一下Reference引用对象是后面提到的软,弱,虚,Final的基类,所以后面的几个引用类型都是基于它来扩展的,如果需要使用最好配合带ReferenceQueue的构造函数进行使用,Reference基于ReferenceQueue进行垃圾回收的。带queue的构造引用,垃圾回收过程中,该对象会经历Active->Pending(等待GC)->Enqueued(入队)->Inactive(完全回收)的状态,这个对象放到队列里的作用就是当我们使用引用的时候,可以查询这个队列,来判断对象内存是否被回收。具体可以看一下源码。下面就介绍具体的子类引用类型。

3.软引用

      如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,才会被GC。只要垃圾回收器没有回收它,该对象就可以被程序使用。

3.1 简单使用

public class SoftReferenceTest {public static void main(String[] args) {SoftReference softReference = new SoftReference(new String("object"));String softObject = (String) softReference.get();}
}

 

3.2 软引用的特点

     SoftReference的特点,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。Java虚拟机的垃圾收集线程对软可及对象和其他一般Java对象进行了区别对待,软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。

具体策略:垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。

3.3 配合ReferenceQueue

      作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。当这个SoftReference所软引用的对象被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。利用这个方法,我们可以检查SoftReference软引用对象是否被回收。

@Test
public void testRefQueue() {ReferenceQueue queue = new ReferenceQueue();//创建一个软引用new SoftReference(new String("xxx"), queue);/*** GC后进行一次手动check,并清除*/SoftReference remove = null;while ((remove = (SoftReference) queue.poll()) != null) {// 清除refSystem.out.println("SoftReference 不为 null,这里进行手动清除");remove.clear();}
}

 

3.4 为什么需要使用软引用?

     在我们平时开发当中,如果我们希望对象尽可能的存在时间长一点,在内存允许的情况下,一些可缓冲的对象就可以使用软引用的方式进行持有对象,或者在一段时间内,该对象使用的频次比较多,过了热点时间,就不会被使用,这样我们可以大大减少没必要的对象再次创建,就像使用缓存一样。所以软引用可用来实现内存敏感的高速缓存,使用软引用能防止内存泄露,增强程序的健壮性。软引用和弱引用都可以解决OOM问题。
例如:软引用的一个使用例子,维护一个用户缓存

/*** @author zhangzuizui* @date 2018/6/27 18:27*/
public class UserCache {private static UserCache userCache;// 用于Chche内容的存储private ConcurrentHashMap<String,UserRef> userRefsMap;// 垃圾Reference的队列private ReferenceQueue<User> queue;private class UserRef extends SoftReference<User> {private String name = "zzz";public UserRef(User user, ReferenceQueue<User> queue) {super(user, queue);name = user.getName();}}// 取得缓存器实例public static UserCache getInstance() {if (userCache == null) {userCache = new UserCache();}return userCache;}// 构建一个缓存器实例private UserCache() {userRefsMap = new ConcurrentHashMap<>();queue = new ReferenceQueue<User>();}// 以软引用的方式对一个User对象的实例进行引用并保存该引用private void cacheUser(User user) {cleanCache();// 清除垃圾引用UserRef ref = new UserRef(user, queue);userRefsMap.put(user.getName(), ref);}// 依据所指定的userName,重新获取相应User对象的实例public User getUser(String userName) {User em = null;// 缓存中是否有该User实例的软引用,如果有,从软引用中取得。if (userRefsMap.containsKey(userName)) {UserRef ref = (UserRef) userRefsMap.get(userName);em = (User) ref.get();}// 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,// 并保存对这个新建实例的软引用if (em == null) {em = new User(userName);System.out.println("new user userName=" + userName);this.cacheUser(em);}return em;}// 清除那些所软引用的User对象已经被回收的UserRef对象private void cleanCache() {UserRef ref = null;while ((ref = (UserRef) queue.poll()) != null) {userRefsMap.remove(ref.name);}}// 清除Cache内的全部内容public void clearCache() {cleanCache();userRefsMap.clear();System.gc();System.runFinalization();}
}

 

4. 弱引用

4.1 弱引用的特点

     弱引用WeakReference也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。弱引用也可以用来操作敏感缓存的对象,配合jvm的自身GC机制,来实现自动回收内存的效果,同样WeakReference也可以和引用队列一起使用。

 public static void main(String[] args) {WeakReference<String> reference = new WeakReference<String>(new String("zzzz"));System.out.println(reference.get());//通知GVM回收资源System.gc();System.out.println(reference.get());}

      执行结果:第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。
例如这样写:

String string = new String("zzzz")
WeakReference<String> reference = new WeakReference<String>(string);

这样两次System.out都会输出“zzzz”

 

4.2 为什么使用弱引用?

      一个长生命周期的对象如果对一个短生命周期的持有引用,那么这个短什么周期的对象一直无法被GC,这是出现内存泄露的一个原因,所以为了避免这种情况,我们可以运用WeakReference来持有该对象的引用,这样就不会出现长生命周期的对象的持有导致内存溢出。比如HashMap持有很对Object对象,其中有短周期的对象可以替换成虚引用。WeakHashMap就是运WeakReference实现的,从它entry子类中可以看出,它的key是WeakReference包裹住的。当这个key对象本身不再被使用时,伴随着GC的发生,会自动把该key对应的entry都在Map中清除掉。

 

5. 虚引用

5.1 虚引用的特点

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

5.2 虚引用的作用

      PhantomReference主要作为其指向的referent被回收时的一种通知机制,它就是利用上文讲到的ReferenceQueue实现的。当referent被gc回收时,可以通过这个通知机制来做额外的清场工作。因此有些情况可以用PhantomReference 代替finalize(),做资源释放更明智。

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

 

6. FinalReference

      FinalReference 引用类型主要是为虚拟机提供的,提供对象被gc前需要执行finalize方法的对象 的机制。只是把访问权限改为package,因此我们是无法直接使用,jVM会对那些实现了Object中finalize()方法的类实例化一个对应的FinalReference,关于具体的细节有兴趣大家可以去看一下Finalizer的源码;
,其中包括Finalizer对象初始化守护线程,jvm注册Finalizer对象(实例化FinalReference),GC后入ReferenceQueue队列,并通知FinalizerThread去消费等操作。关于finalize方法的使用可以和该引用和串起来思考,后边有必要再总结一篇关于finalize的文章。

 

7. 打印GC引用日志:

-XX:+PrintGCDetails
0.194: [GC (System.gc()) 0.196: [SoftReference, 0 refs, 0.0000125 secs]0.196: [WeakReference, 11 refs, 0.0000064 secs]0.196: [FinalReference, 37 refs, 0.0000138 secs]0.196: [PhantomReference, 0 refs, 0 refs, 0.0000058 secs]0.196: [JNI Weak Reference, 0.0000417 secs]
0.196: [Full GC (System.gc()) 0.197: [SoftReference, 0 refs, 0.0000115 secs]0.197: [WeakReference, 3 refs, 0.0000071 secs]0.197: [FinalReference, 0 refs, 0.0000077 secs]0.197: [PhantomReference, 0 refs, 0 refs, 0.0000074 secs]0.197: [JNI Weak Reference, 0.0000276 secs]

 

8. 总结

      通过对SoftReference,WeakReference,PhantomReference,FinalReference 的介绍,可以看出JDK提供这些类型的reference 主要是用来和GC交互的,根据reference的不同,让JVM采用不同策略来进行对对象的回收(reclaim)。softly-reachable的referent在保证在OutOfMemoryError之前回收对象,weakly-reachable的referent在发生GC时就会被回收,finalizer型的reference 主要提供GC前对referent进行finalize执行机制。同时这些reference和referenceQueue在一起提供通知机制,PhantomReference的作用就是仅仅就是提供对象回收通知机制,Finalizer借助这种机制实现referent的finalize执行,SoftReference、WeakReference也可以配合referenceQueue使用,实现对象回收通知机制。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“雪花”项目:Microsoft探索在.NET中实现手工内存管理

来自Microsoft研究院、剑桥大学和普林斯顿大学的一些研究人员构建了一个.NET的分支&#xff0c;实现了在运行时中添加支持手工内存管理的API。研究方法的细节及所获得的性能提升发表在名为“Project Snowflake: Non-blocking Safe Manual Memory Management in .NET”&#xff…

loj#10050-The XOR Largest Pair【Trie(字典树)】

正题 题目链接:https://loj.ac/problem/10050 题目大意 有n个数&#xff0c;求两个数使他们异或起来最大。 解题思路 我们考虑构建一个TrieTrie。 两个分叉为0,1&#xff0c;对于每个数二进制下不够30位我们将其补够30位&#xff0c;然后再根据二进制01构建TrieTrie。 然后…

publiccms按照指定显示的日期格式,格式化日期的写法

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2021年12月30日20:21:37&#xff0c;距离2021年结束仅仅不到2天的时间了&#xff0c;时间恍如白驹过隙&#xff01; 今天还是搞的publiccms,分享个简单的语法吧&#xff1a;在…

PL/SQL之JOB用法 (定时跑数据)

转载自 PL/SQL之JOB用法 (定时跑数据) 一、DBMS_Job包的用法 包含以下子过程&#xff1a; Broken()过程。 change()过程。 Interval()过程。 Isubmit()过程。 Next_Date()过程。 Remove()过程。 Run()过程。 Submit()过程。 …

Orleans解决并发之痛(四):Streams

Orleans 提供了 Stream扩展编程模型。此模型提供了一套API&#xff0c;使处理流更简单和更健壮。Stream默认提供了两种Provider&#xff0c;不同的流类型可能使用不同的Provider来处理&#xff0c;Simple Message Stream Provider 和 Azure Queue Stream Provider。Stream Prov…

POJ3764-The xor-longest Path【Trie(字典树)】

正题 POJ题目链接:http://poj.org/problem?id3764 其实loj也有题目:https://loj.ac/problem/10056 题目大意 一棵树&#xff0c;求两个点使他们的之间的边的异或值最大。 解题思路 我们可以先算出所以点离根的路上的边的异或值&#xff0c;记为didi&#xff0c;然后根据异…

2022的第一天,立个目标

时光如白驹过隙&#xff0c;一晃已经20多年过去了&#xff0c;在这些年中&#xff0c;可谓社会的百般形态都已经历过…… 14年辍学&#xff0c;独自一人来到济南打工。15年辞职&#xff0c;开始上学学计算机。16年继续学习。17年毕业&#xff0c;以优秀的成绩被留校任用为教员…

Oracle的分页实现

转载自 Oracle的分页实现 在Oracle中实现分页的方法大致分为两种&#xff0c;用ROWNUM关键字和用ROWID关键字&#xff0c;下面来详细介绍一下&#xff1a; 1、ROWNUM 其代码为&#xff1a; SELECT *FROM (SELECT ROW_.*, ROWNUM ROWNUM_FROM (SELECT *FROM TABLE1WHERE TA…

如何编写更好的SQL查询:终极指南-第二部分

上一篇文章《如何编写更好的SQL查询&#xff1a;终极指南-第一部分》中&#xff0c;我们学习了 SQL 查询是如何执行的以及在编写 SQL 查询语句时需要注意的地方。 下面&#xff0c;我进一步学习查询方法以及查询优化。 基于集合和程序的方法进行查询 反向模型中隐含的事实是…

POJ3349,洛谷SP4354-SnowflakeSnowSnowflakes【最小表示法,hash】

正题 洛谷评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidSP4354 POJ题目链接:http://poj.org/problem?id3349 题目大意 有n片雪花&#xff0c;他们6个角有不同的长度&#xff0c;如果两片雪花6个角长度相同&#xff08;可以不同方向&#xff09;&#…

publiccms实现遍历多级分类下的不同样式内容

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年1月2日17:06:51,假期这两天都在做publiccms。 上篇文章遗留的问题&#xff0c;最终还是没有按照富文本去做&#xff0c;后期在看吧&#xff1b; 今天遇到了个问题&…

四张图带你了解Tomcat系统架构--让面试官颤抖的Tomcat回答系列

转载自 四张图带你了解Tomcat系统架构--让面试官颤抖的Tomcat回答系列 俗话说&#xff0c;站在巨人的肩膀上看世界&#xff0c;一般学习的时候也是先总览一下整体&#xff0c;然后逐个部分个个击破&#xff0c;最后形成思路&#xff0c;了解具体细节&#xff0c;Tomcat的结构…

.NET Core 2.0应用程序大小减少50%

.NET Core 2.0应用程序减小体积瘦身官方工具 IL Linker。 IL Linker 来源于mono的linker https://github.com/mono/linker&#xff0c;目前还是预览版本。 在一般的情况下&#xff0c;链接器可以将应用程序的大小减少50&#xff05;&#xff0c;大型应用程序的大小可能更有利…

P1368-工艺【最小表示法】

正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP1368 题目大意 n个块&#xff0c;可以进行若干次将最左边的方块放在最右边&#xff0c;然后如果前面那个比后面那个瑕疵度小那么前面那个就是美丽的&#xff0c;求一个让最美丽的序列。 解题思路 求…

Orleans解决并发之痛(五):Web API

通过前面几篇文章的介绍&#xff0c;可能会疑问怎么在实际开发中调用Grain&#xff0c;之前Demo的Client都是基于控制台应用程序&#xff0c;实际开发下可能是基于Web Form、Web API、MVC......&#xff0c;由于一时短路了&#xff0c;没有联想到控制台应用程序的方式怎么切到其…

ASP.Net Core WebApi几种版本控制对比

一、版本控制的好处&#xff1a; &#xff08;1&#xff09;有助于及时推出功能, 而不会破坏现有系统。 &#xff08;2&#xff09;它还可以帮助为选定的客户提供额外的功能。 API 版本控制可以采用不同的方式进行控制&#xff0c;方法如下&#xff1a; &#xff08;1&…

POJ2279-Mr. Young's Picture Permutations【线性dp】

正题 题目链接:http://poj.org/problem?id2279 题目大意 有k列&#xff0c;每列人数不同&#xff0c;要求从左到右和从前到后身高都单调递减&#xff0c;学生高度是1∼N1∼N(人数总和) 解题思路 我们开一个五维数组&#xff0c;然后每次在人少那列填充&#xff0c;按照这总…

JoyOI(TYVJ)1071-LCIS【线性dp,LIS,LCS】

正题 题目链接:http://www.joyoi.cn/problem/tyvj-1071 题目大意 求两个序列的最长公共上升子序列。 code 我们先回顾一下LIS和LCS LIS:fimax{fj1}(j<i,aj<ai)fimax{fj1}(j<i,aj<ai)LCS:fi,jmax⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪fi−1,jfi,j−1fi−1,j−11(a…

asp.net core策略授权

在《asp.net core认证与授权》中讲解了固定和自定义角色授权系统权限&#xff0c;其实我们还可以通过其他方式来授权&#xff0c;比如可以通过角色组&#xff0c;用户名&#xff0c;生日等&#xff0c;但这些主要取决于ClaimTypes&#xff0c;其实我们也可以自定义键值来授权&a…

Safari浏览器不支持let声明的解决方式

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年1月7日16:19:38,前几天用publiccms改了个网站&#xff0c;因为客户那边各种机型都有&#xff08;各PC端的分辨率也都不一样&#xff09;&#xff0c;所以导致页面呈现的效…