弱,弱,最弱,利用专业参考来利用垃圾收集器

何时以及何时不使用Java中的专家引用

弱引用,软引用和幻像引用是危险且强大的。 如果以错误的方式使用它们,则会破坏JVM性能。 但是,如果使用正确的方法,它们可以大大提高性能和程序清晰度。

弱引用和软引用在这三个中更为明显。 实际上,它们几乎是同一件事! 这个想法很简单,就是将它们用于访问对象,但不会阻止垃圾回收器回收该对象:

Object y=new Object();
// y is a hard reference to the object
// and so that object cannot be reclaimed.Obejct x=WeakReference<Object>(y);
// now x is a weak reference to the object
// (not to y - as y is just a variable).
// The object still cannot be reclaimed 
// because y is still a hard reference to it.y=null;
// now there is only a weak reference to 
//the object, it is eligible for garbage collection.if(x.get()==null){System.out.println("The object has gone away");
}else{System.out.println("The object is " + x.get().toString());
}

您发现故意的错误吗? 这是一个容易错过的东西,并且可能不会在单元测试中显示。 正是这种问题使我说:

仅在绝对必要且可能甚至没有的情况下,才使用弱/软引用。

当JVM承受内存压力时,它可能会在弱引用中的get方法的第一次和第二次调用之间回收该对象。 当在null上调用toString方法时,这将导致程序引发null指针异常。 该代码的正确形式为:

Object x=x.get();
// Now we have null xor a hard reference to
// the object
if(z==null){System.out.println("The object has gone away");
}else{System.out.println("The object is " + z.toString());
}

我们为什么要他们?

我们还没有完全谈到为什么它们真的非常危险。 为此,我们需要了解为什么我们可能需要它们以及为什么我们需要它们。 在两种常见的情况下,弱引用和软引用似乎是一个好主意(我们将在稍后介绍软和弱引用之间的区别)。 首先是某种形式的RAM缓存。

它是这样的:

我们有一些数据,例如客户详细信息,存储在数据库中。 我们一直在寻找它,这很慢。 我们可以做的是将这些数据缓存在RAM中。 但是,最终RAM将填充名称和地址,并且JVM抛出OutOfMemoryError。 解决方案是将名称和地址存储在只能弱访问的对象中。 像这样:

ConcurrentHasMap>String,WeakReference>CustomerInfo<< cache=new ConcurrentHashMap><();
...
CustomerInfo currentCustomer=cache.get(customerName);
if(currentCustomer==null){currentCustomer=reloadCachesEntry(customerName);
}

这种无害的小模式非常有能力使巨型的JVM崩溃。 该模式正在使用JVM的垃圾回收器来管理内存中的缓存。 垃圾收集器从未被设计为这样做。 该模式通过用难以到达的对象填充内存来滥用垃圾收集器,这些对象使JVM耗尽了堆空间。 当JVM的内存不足时,它必须遍历其堆中的所有引用(弱引用,软引用和其他引用)并回收RAM。 这是昂贵的并且显示为处理成本。 在具有许多处理器核心的超大型JVM实例上,情况甚至更糟,因为垃圾收集器很可能最终不得不执行“停止世界”的完整循环,从而将性能降低到单个核心级别!

我并不是说内存缓存技术不是一个好主意。 哦,不,这是个好主意。 但是,仅将其扔到垃圾收集器上并且不期望麻烦是非常糟糕的设计选择。

弱vs软

有什么区别? 好吧,真的有很多。 在某些JVM(例如客户端托管JVM)上,但弱引用可能会标记为优先垃圾收集。 换句话说,与其他内存相比,垃圾回收器应更努力地从它们引用的对象图中回收内存(并且不引用软或硬引用)。 软引用对他们没有这个想法。 但是,这只是某些JVM上的可选想法,不能被依赖,无论如何这都是一个坏主意。 我建议始终使用软引用或弱引用,并坚持使用它。 选择您喜欢的声音。 我更喜欢WeakReference这个名字,所以倾向于使用它。

还有一个区别。 一个由软引用弱引用而不是硬引用引用的对象可能会遇到这样的情况,即仍然可以从弱引用的.get()方法中获取,而不能从软引用的.get()方法中获取。 反之亦然,反之亦然。 依赖此行为的代码可能是错误的标题。

弱引用的良好用法

确实存在。 弱引用对于跟踪在其他地方使用的对象很有用。 一个示例来自Sonic Field(音频处理程序包)。 在此示例中,文件中的“插槽”包含音频数据,并与内存中的对象相关联。 该模型不使用弱引用来引用数据的内存中副本。 在内存对象中使用插槽。 弱引用用于允许文件管理系统重用插槽。

使用插槽的代码不需要(也不需要)与磁盘空间的管理有关。 文件管理器很关心这样做。 文件管理器对使用插槽的对象有较弱的引用。 当请求一个新的插槽时,文件管理器将检查通过弱引用引用的所有现有插槽,这些弱引用已被回收(因此从get方法返回null)。 如果找到这样的引用,则可以重用该插槽。

自动通知回收

有时我们可能想知道何时已收回弱引用或软引用(或其他类型的幻像)。 这可以通过排队系统来完成。 我们可以使用参考队列来做到这一点:

WeakReference(T referent, ReferenceQueue<? super T> q)

我们做这样的事情:

ReferenceQueue junkQ = new ReferenceQueue<>();
....
WeakReference<FileSlot> mySlot=new WeakReference<>(aSlot);
....
// In a different thread - make sure it is daemon!
WeakReference<FileSlot> isDead;
while(true){isDead = junkQ.remove();// Take some action based on the fact it is dead// But - it might not be dead - see end of post :(
...
}

但是,请记住,当弱引用在junkQ上结束时,对其调用.get()将返回null。 如果您必须存储信息以允许您感兴趣的任何操作发生在其他地方(例如,ConcurrentHashMap,其中引用是关键),

那么什么是幻影引用?

幻像引用是一种,当您需要它们时,您确实需要它们。 但是从表面上看,它们似乎毫无用处。 您会看到,每当在幻影引用上调用.get()时,始终会返回null。 永远不可能使用幻像引用来引用它所引用的对象。 好吧-这不是真的。 有时我们可以通过JNI来实现这一目标,但我们绝对不应该这样做。

考虑一下您在与Java对象关联的JNI中分配本机内存的情况。 JDK的noi包中的DirectBuffers使用的就是这种模型。 这是我在大型商业项目中反复使用的东西。

那么,我们如何回收本机内存?

对于类似文件的系统,可以说直到关闭文件才回收内存。 这将资源管理的责任放在程序员的肩膀上; 这正是程序员对文件之类的期望。 但是,对于重量较轻的对象,我们的程序员不喜欢考虑资源管理-垃圾收集器可以为我们做这些事情。

我们可以将代码放在终结器中,终结器调用JNI代码来回收内存。 这是很糟糕的(就像致命的那样),因为JVM几乎保证它们将调用终结器。 所以,不要那样做! 但是,幻象引用可以解救! 首先,我们需要理解“幻影可到达”:只有在无法通过任何其他种类的参考(硬,弱或软)到达幻像引用时,它才会被排队。 在这一点上,幻影参考可以入队。 如果对象具有终结器,则它将被忽略或运行。 但它不会“将物体带回生活”。 幻影可到达对象对于JNI本机代码(或任何其他代码)来说是“安全的”,可以根据资源回收资源。

因此,带有幻像引用的代码如下所示:

ReferenceQueue<FileSlot> junkQ = new ReferenceQueue<>();
....
Phantom<FileSlot> mySlot=new Phantom<>(aSlot);
....
// In a different thread - make sure it is daemon!
Phantom<FileSlot> isDead;
while(true){isDead=junkQ.remove();long handle=lookUpHandle(isDead);cleanNativeMemory(handle);
}

在这种模式下,我们保留了一个句柄,本机代码可使用该句柄在Java中的结构(可能是另一个哈希图)中查找和回收资源。 当我们完全确定Java对象无法重生时-它是幻影可到达的(例如,幽灵-我们可以安全地回收本机资源。如果您的代码使用sun.misc.unsafe进行了其他“顽皮的”事情(对于有关使用此技术的完整示例,请参见这篇文章 。

关于幻影引用的最后思考。 从技术上讲,可以使用弱引用来实现与上述相同的模式。 但是,这并不是弱引用的目的,并且这种模式会滥用它们。 幻象引用绝对保证对象确实已死,因此可以回收资源。 仅举一个例子,理论上就有可能使弱引用入队,然后通过终结器将对象恢复生命,因为终结队列的运行速度比弱参考队列慢。 这种幻影恐怖故事不可能在幻影引用中发生。

有一个小问题,这是JVM设计的弱点。 也就是说,JNI全局弱引用类型与幻像引用具有未定义的关系。 有人建议即使将对象排队为幻像引用,也可以使用全局弱引用来获取对象。 这是对JVM的一种特定实现的怪癖,切勿使用。
参考: 弱,更弱,最弱,利用垃圾收集器 ,以及来自Java日历日历博客上我们JCG合作伙伴 Alexander Turner的专业参考 。

翻译自: https://www.javacodegeeks.com/2012/12/weak-weaker-weakest-harnessing-the-garbage-collector-with-specialist-references.html

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

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

相关文章

bootstrap的栅格系统和响应式工具

关于bootstrap的响应式布局&#xff0c;昨天看了杨老师的视频教学https://www.bilibili.com/video/av18357039豁然开朗&#xff0c;在这里记录一下 一&#xff1a;meta标签的引用 <meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" conte…

【区块链Go语言实现】Part 1:区块链基本原型

0x00 介绍 区块链&#xff08;Blockchain&#xff09;是21世纪最具革命性的技术之一&#xff0c;目前它仍处于逐渐成熟阶段&#xff0c;且其发展潜力尚未被完全意识到。从本质上讲&#xff0c;区块链只是一种记录的分布式数据库。但它之所以独特&#xff0c;是因为它并不是一个…

Java_基础—FileOutputStream

package com.soar.stream;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class Demo2_FileOutputStream {/** FileOutputStream 在创建对象的时候&#xff0c;如果没有这个文件会帮我们创建出来* 如果有这个文件…

小熊错误_新手爸妈第一年带娃时,很容易犯的7个错误,对照看看你中了没

文 /关注小熊育儿&#xff0c;帮您轻松育儿带娃不是一件容易的事&#xff0c;对爸妈的时间和体力都是一种考验&#xff0c;不仅“熊孩子”让人头疼&#xff0c;育儿知识差&#xff0c;不懂科学育儿理念的“熊爸妈”也是让人很无奈的&#xff0c;最终受伤的还是孩子&#xff0c;…

轻量级Web应用程序框架:PrimeFaces(JSF)+ Guice + MyBatis(第2部分)

在这一部分中&#xff0c;我将继续演示JSF&#xff0c;Guice和MyBatis的集成。 在持久层中使用DBCP连接池和MYSQL数据库。 看一下第1部分 。 在上一篇文章中 &#xff0c;我们创建了一个ServletContextListener。 现在&#xff0c;我们只需要在contextInitialized方法中绑定Ba…

python--装饰器、生成器、迭代器、元类

一、装饰器 def w1(func):def inner():func()return innerw1 def f1():print(1111111) 1.只要python解释器执行到装饰器&#xff0c;就会自动进行装饰&#xff0c;而不是等到调用的时候才进行装饰。 2.有参数的函数&#xff0c;装饰器定义方法 def w1(func):def inner(*args, *…

scss的使用方式(环境搭建)

我用的是Koala。 IDE是intellij_idea&#xff08;其他IDE也可&#xff09; 下载Koala&#xff1a;http://koala-app.com/ 2.安装&#xff08;选好位置&#xff0c;下一步即可&#xff09; 3.打开Koala&#xff0c;创建项目 》创建css文件夹》创建XXX.scss文件&#xff0c;拖到…

小程序 按需_小程序想要留住用户需哪些举措?

**当下许多企业在进行长沙小程序开发后&#xff0c;都会费劲心思在推广引流上&#xff0c;很多企业也确实起到了不错的效果&#xff0c;用户们也是纷纷来到企业的小程序中。只不过有的小程序却无法将用户留下来&#xff0c;导致用户流失&#xff0c;令推广付之东流。下面长沙小…

渍渍渍~来一发豆瓣自动登录玩玩~

今天来一个比较屌的自动化登陆工具&#xff0c;selenium模块&#xff0c;这个模块&#xff0c;比较装逼啦~具体自行百度吧&#xff01;这篇博客实现了什么功能呢~可以自动使用用户名和密码登录&#xff0c;当然&#xff0c;豆瓣对登录次数还有ip地址做了一些策略&#xff0c;例…

Redis数据库入门学习(下载与安装、常用命令、在Java中操作Redis)

简介 下载与安装 数据类型 常用命令 1.字符串操作命令 2.哈希操作命令 3.列表操作命令 push是将元素总是插入到第一个 0表示第一个&#xff0c;1表示第二个。-1表示倒数第一个&#xff0c;-2表示倒数第二个。当前命令的意思是第一个到倒数第一个&#xff0c;即就是全部元素 rpo…

Java EE 7公共草案已发布。 我需要Java EE Light Profile!

2012年12月20日&#xff0c;Java EE 7的公共草案已上载。 乍一看&#xff0c;新规范是对Java EE 6中后续规范的改进。例如&#xff0c;我真的很喜欢Web Profile的想法。 遗憾的是它不是Java EE 6 Web Profile的一部分。 Web Profile是针对现代Web应用程序IMO的开发人员的&…

css入门基础知识

属性的值大于一个单词&#xff0c;要加上引号。 外部样式表<link href "mycss.css" type"text/css" rel "stylesheet">href是css文件&#xff0c;类型是text/css,rel是当前文档与外部文档的关系。 内部样式表<style>body{color:re…

.NET使用Office Open XML导出大量数据到 Excel

我相信很多人在做项目的都碰到过Excel数据导出的需求&#xff0c;我从最开始使用最原始的HTML拼接&#xff08;将需要导出的数据拼接成TABLE标签&#xff09;到后来happy的使用开源的NPOI, EPPlus等开源组件导出EXCEL&#xff0c;但不久前&#xff0c;我在一个项目碰到一个需求…

netapp管理地址_NetApp常用管理命令总结

一、系统相关&#xff1a;sysconfig -v查看硬件信息,主要显示了硬件平台、版本、序列号、适配器(网卡、光纤卡等)、硬盘等硬件信息sysconfig -r显示磁盘、raid、volume信息&#xff0c;等同于vol status -r-每个RAID会显示RAID的类型、RAID中每个磁盘是属于数据盘(data)、校验盘…

Java 8中的默认方法(Defender方法)简介

我们都知道Java中的接口仅包含方法声明&#xff0c;而没有实现&#xff0c;并且任何实现该接口的非抽象类都必须提供实现。 让我们看一个例子&#xff1a; public interface SimpleInterface {public void doSomeWork(); }class SimpleInterfaceImpl implements SimpleInterfa…

CSS自定义消息提示

1.效果 2.源码 <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head><style type"text/css">#confirm{position: absolute;z-index: 1;display: inline-block;border: 1px solid black;backgr…

转 push本地代码到github出错

https://www.douban.com/note/332510501/ 刚创建的github版本库&#xff0c;在push代码时出错&#xff1a;$ git push -u origin masterTo gitgithub.com:******/Demo.git! [rejected] master -> master (non-fast-forward)error: failed to push some refs to gitgithub.co…

go语音实战读后感——一

1、第一个go程序&#xff1a; package mainimport ("fmt" )func main() {fmt.Println("Hello go") } 解析&#xff1a;package引进go程序组织包&#xff0c;通过import导入外部代码&#xff0c;标准库中的fmt包用于格式化并输出;通过main主函数进行执行程序…

file 选择的文件胖多有多大_如何删除 macOS 压缩包中的隐藏文件?

如何删除 macOS 压缩包中的隐藏文件&#xff1f;在工作中&#xff0c;压缩打包文件是不可缺少的一项工作。为了避免文件的损坏和缺失&#xff0c;我们通常在macOS系统中&#xff0c;把多个文件或文件夹压缩后进行传输&#xff0c;我们一般使用访达&#xff08;Finder&#xff0…

使用Camel在来自不同来源的Solr中索引数据

Apache Solr是建立在Lucene之上的“流行的&#xff0c;快速的开源企业搜索平台”。 为了进行搜索&#xff08;并查找结果&#xff09;&#xff0c;通常需要从不同的来源&#xff08;例如内容管理系统&#xff0c;关系数据库&#xff0c;旧系统&#xff09;中提取数据&#xff0…