java虚引用作用_深入理解Java中的引用(二)——强软弱虚引用

深入理解Java中的引用(二)——强软弱虚引用

在上一篇文章中介绍了Java的Reference类,本篇文章介绍他的四个子类:强引用、软引用、弱引用、虚引用。

强引用(StrongReference)

强引用是我们在代码中最普通的引用。示例代码如下:

Object o = new Object(); // 强引用

在JVM的GC算法中,如果一个对象具有强引用,那么JVM宁可抛出Out of Memory错误,垃圾回收器也不会去回收这个对象。

当在代码里显示的写o = null,或者该对象的引用作用域是在一个函数里,代码如下,当线程调用完test,就会退出方法栈,引用不存在,垃圾回收器才会在某个时刻回收Object对象。

public void test(){

Object o = new Object(); // 强引用

}

软引用(SoftReference)

如果一个对象有一个软引用,那么在内存足够的情况下,该对象就不会被垃圾回收器回收。网上有很多资料说软引用只会在内存空间不够用的情况下对象才会被回收。 那么什么时候才是内存不够用呢?

首先看一下SoftReference类的源码可以看到有两个字段。这两个字段的作用已经标注,这与JVM GC有什么关系呢?

/**

* 记录最近一次被GC的时间。

*/

static private long clock;

/**

* 每次调用get方法的时候更新

* 记录当前Reference最近一次被访问的时间

*/

private long timestamp;

一起看一下HotSpot的源码,对于软引用的回收策略见下面should_clear_reference函数。

// The oop passed in is the SoftReference object, and not

// the object the SoftReference points to.

bool LRUMaxHeapPolicy::should_clear_reference(oop p,

jlong timestamp_clock) {

jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p);

assert(interval >= 0, "Sanity check");

// The interval will be zero if the ref was accessed since the last scavenge/gc.

if(interval <= _max_interval) {

return false;

}

return true;

}

上述代码中interval表示当前引用存活了多久。他的值就是对应上述java代码中的clock与timestamp相减。interval与_max_interval比较,如果大于 _max_interval,那么就和弱引用一样处理,如果小于就当做强引用处理。_max_interval的赋值函数如下:

// Capture state (of-the-VM) information needed to evaluate the policy

void LRUMaxHeapPolicy::setup() {

size_t max_heap = MaxHeapSize;

max_heap -= Universe::get_heap_used_at_last_gc();

max_heap /= M;

_max_interval = max_heap * SoftRefLRUPolicyMSPerMB;

assert(_max_interval >= 0,"Sanity check");

}

通过源码可见首先是max_heap减去上次GC之后剩余堆大小,如果上次GC之后还有很多剩余空间,说明内存空间不够用了,那么max_heap的值就越小,相应_max_interval也越小,软引用就越可能被回收。

软引用的一个作用是实现内存敏感的高速缓存。比如浏览器的后退按钮,

(1)如果网页浏览结束就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建。

(2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出。

通过软引用可以解决该问题

Browser prev = new Browser(); // 获取页面进行浏览

SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用

if(sr.get()!=null){

rev = (Browser) sr.get(); // 还没有被回收器回收,直接获取

}else{

prev = new Browser(); // 由于内存吃紧,所以对软引用的对象回收了

sr = new SoftReference(prev); // 重新构建

}

弱引用(WeakReference)

只具有弱引用的对象生命周期更短。当垃圾回收器发现了只有弱引用的对象时候,无论内存空间是否足够,都会被GC回收。当你偶尔需要引用某个对象,随时能获取该对象,但是不想介入该对象的生命周期的时候,就可以使用弱引用, 因为弱引用不会对对象的垃圾回收判断产生附加的影响。

当弱引用绑定的对象被垃圾回收的时候,JVM会把这个弱引用加入到相关联的ReferenceQueue中。

这里抛出两个问题:

(1)弱引用什么时候会被加入到ReferenceQueue中,由什么决定的呢?

(2)如果绑定的对象GC之后存活了下来,弱引用怎么知道这个对象的新地址呢?

第一种情况,GC扫描到只存在弱引用的时候就会把它放到链表里。还有第二种情况:一个对象既有强引用又有弱引用的情况

下面通过图片来解释上面两个问题:

e279b8b492aa

image.png

上图表示C同时存在两个引用:强引用A和弱引用B。

第一种情况:GC先扫描到A

这种情况下GC同时会扫描到C,A和C都会搬到Survivor区。然后扫描到B,发现B引用的C搬到到了新的Survivor,这个时候就把B也搬到Survivor,并把C的新地址更新到B,结果如下:

e279b8b492aa

image.png

第二种情况:GC先扫描到B

GC还是会先把B放到ReferenceQueue中,由于C还是存活的,所以B会被搬到Survivor中。然后扫描到A,A和C都会搬到Survivor中,GC结束的时候B所指向的对象就不对了,如下图所示

e279b8b492aa

image.png

该情况下会重新遍历ReferenceQueue,发现绑定的对象依然存活,C‘ 的指针是指向C的,于是就把B再指向C就可以了,同时因为C依然存活,把B从ReferenceQueue中移除。新的地址空间如下图所示:

e279b8b492aa

image.png

具体过程可以查看海纳知乎专栏。

虚引用(PhantomReference)

虚引用不会对对象的垃圾回收有任何附加影响,他与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。查看他的构造方法可以看到必须与一个ReferenceQueue绑定,而且他的get方法返回的一直是null

public T get() {

return null;

}

public PhantomReference(T referent, ReferenceQueue super T> q) {

super(referent, q);

}

虚引用主要用在跟踪对象垃圾回收的状态。具体应用会在在下一节讲到DirectByteBuffer 与ThreadLoal回收的时候详细分析。

总结

关于强引用、软引用、弱引用与虚引用在垃圾回收时的区别可以用下图表示:

e279b8b492aa

image.png

下图总结了四种引用在其他方面的区别:

e279b8b492aa

image.png

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

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

相关文章

SQL查询表的列名

SELECT COLUMN_NAME FROM DBA_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME DT4_JOB_CHECK_MATRIX;

java老鸟123怎么样_java入门123——一个老鸟的java学习心得.doc

java入门123——一个老鸟的java学习心得java入门123——一个老鸟的java学习心得篇一&#xff1a;java初学者学习心得学习Java心得体会学习了一学期的Java课程,觉得是该总结自己的心得体会了。开始学习任何一门课(包括java)&#xff0c;兴趣最重要。一直觉得自己在学计算机编程语…

ruby 爬虫爬取拉钩网职位信息,产生词云报告

思路&#xff1a;1.获取拉勾网搜索到职位的页数 2.调用接口获取职位id 3.根据职位id访问页面&#xff0c;匹配出关键字 url访问采用unirest&#xff0c;由于拉钩反爬虫&#xff0c;短时间内频繁访问会被限制访问&#xff0c;所以没有采用多线程&#xff0c;而且每个页面访问时间…

评论语义分析 分词 分类python_用python调用ICTCLAS50进行中文分词

直接上源码吧tokenizer类&#xff1a;#_*_encoding:utf-8_*_from ctypes import *class tokenizer:def __init__(self):self._stext[、,“,”,&#xff0c;,。,《,》,&#xff1a;,&#xff1b;,!,‘,’,?,&#xff1f;,&#xff01;,, ,] #枚举标点符号包括空格self._stopwor…

java对日期Date类进行加减运算、年份加减,月份加减

JAVA处理日期时间常用方法&#xff1a; 1.Java.util.Calendar Calendar 类是一个抽象类&#xff0c;它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法&#xff0c;并为操作日历字段&#xff08;例如获得下星期的日期&#xff09…

idle扩展插件_Python3.4学习笔记之 idle 清屏扩展插件用法分析

本文实例讲述了Python3.4 idle 清屏扩展插件用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;python idle 清屏问题的解决&#xff0c;使用python idle都会遇到一个常见而又懊恼的问题——要怎么清屏?在stackoverflow看到这样两种答案&#xff1a;1.在shell中输入…

内存堆和栈的区别

原文链接&#xff1a;http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html -------------------------------------------------------------------------------- 在计算机领域&#xff0c;堆栈是一个不容忽视的概念&#xff0c;我们编写的C语言程序基本上都要用…

MYSQL安装和配置

Win10安装MySQL5.7.22 解压缩版&#xff08;手动配置 1.下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接点击下载项 下载后&#xff1a; 2.可以把解压的内容随便放到一个目录&#xff0c;我的是如下目录&#xff08;放到C盘的话&#xff0…

python删除过期文件_python删除过期文件的方法

本文实例讲述了python删除过期文件的方法。分享给大家供大家参考。具体实现方法如下&#xff1a;# remove all jpeg image files of an expired modification date mtime# you could also use creation date (ctime) or last access date (atime)# os.stat(filename) returns …

【很久之前的一篇老文章】一位程序员工作10年总结的13个忠告

展望未来&#xff0c;总结过去10年的程序员生涯&#xff0c;给程序员小弟弟小妹妹们的一些总结性忠告。 走过的路&#xff0c;回忆起来是那么曲折&#xff0c;把自己的一些心得体会分享给程序员兄弟姐妹们&#xff0c;虽然时代在变化&#xff0c;但是很可能你也会走我已经做过的…

apply()与call()的区别

一直都没太明白apply()与call()的具体使用原理&#xff0c;今日闲来无事&#xff0c;决定好好研究一番。 JavaScript中的每一个Function对象都有一个apply()方法和一个call()方法&#xff0c;它们的语法分别为&#xff1a; /*apply()方法*/ function.apply(thisObj[, argArray]…

java代码执行了两次_Java中JComboBox的itemStateChanged事件执行两次的解释

今天做项目&#xff0c;用到了JComboBox&#xff0c;即下拉列表框。为了在被选中的项发生改变时获得被选中的项&#xff0c;所以使用的ItemStateChanged事件&#xff0c;可是问题就来了&#xff0c;每次触发该事件&#xff0c;它都执行两次&#xff0c;屡试不爽。一开始以为是代…

python连接mongo_使用简单的Python连接访问MongoDB

继续来聊MongoDB。MongoDB作为了一个数据库产品软件&#xff0c;除了服务器Server端进程(mongod)外&#xff0c;还提供了比较丰富的访问连接接口。我们最常用的就是两个类型&#xff0c;一个是原生mongo shell&#xff0c;另一个就是应用程序语言访问接口。1、从Mongo Shell到应…

spring与mybatis三种整合方法

原文链接&#xff1a;http://www.cnblogs.com/wangmingshun/p/5674633.html ------------------------------------------------------------------------------------------------- 1、采用MapperScannerConfigurer&#xff0c;它将会查找类路径下的映射器并自动将它们创建成…

js常用的2中排序方法:冒泡排序和快速排序

冒泡排序&#xff1a;例如9 4 5 6 8 3 2 7 10 1 首先&#xff1a;9和4比较 4放前 4 9 5 6 8 3 2 7 10 1 4和5比较 4不动 4 9 5 6 8 3 2 7 10 1 4和6比较 4不动 4 9 5 6 8 3 2 7 10 1 4和3比较 3放前 3 9 5 6 8 4 2 7 10 1 3和2比较 2放前 2 9 5 6 8…

java 注册页面正则式_Java使用正则表达式对注册页面进行验证功能实现

本文给大家介绍java使用正则表达式对注册页面进行验证的代码&#xff0c;代码如下所示&#xff1a;package regex;import java.util.Scanner;import java.util.regex.Matcher;import java.util.regex.Pattern;public class registered {public static void main(String[] args)…

python 编程效率_如何有效提升数据分析效率?五大Python技巧

如何有效提升数据分析效率&#xff1f;相信这是所有数据分析工作者都想解决的问题。本文整理了五大python技巧&#xff0c;分别是Pandas Profiling&#xff1b;使用 Cufflinks 和 Plotly 绘制 Pandas 数据&#xff1b;IPython 魔术命令&#xff1b;Jupyter 中的格式编排&#x…

please select a vaild python interpret

当 JetBrains PyCharm 2017.1.3 x64 遇到 please select a vaild python interpret 错误时&#xff1a; 进入PyCharm setting 选项&#xff0c;搜索 interpret

Grafana分析Nginx日志

配置Groub by -Terms时报错&#xff0c;提示需要设置fielddatatrue&#xff0c;报错内容大概如下&#xff1a; "Fielddata is disabled on text fields by default ... " 解决方法如下&#xff1a; https://www.elastic.co/guide/en/elasticsearch/reference/curren…

php curl json post请求_php post请求发送json对象数据参数

网页中发送请求时&#xff0c;大部分情况都参数以键值组合发送数据的&#xff0c;而一些第三方如java开发的接口中需要发送post请求&#xff0c;请求参数为json类型。既然要发送json数据&#xff0c;首页我们需要在请求头中定义数据类型为json&#xff0c;告诉服务器客服端发送…