文章采集调用(【干货】强引用、软引用和幻象引用有什么区别?)

优采云 发布时间: 2021-09-19 16:05

  文章采集调用(【干货】强引用、软引用和幻象引用有什么区别?)

  强参考、软参考、弱参考和幻影参考之间有什么区别

  1.definition

  强引用是最常见的对象引用。只要有一个指向某个对象的强引用,它就可以指示该对象仍然是“活动的”,并且垃圾采集器不会接触该对象。对于普通对象,如果没有其他引用关系,只要它超出引用的范围或显式地将相应的(强)引用分配给null,就可以对其进行垃圾采集。当然,具体的回收时间取决于垃圾采集策略

  特点:在我们典型的代码中,Obj=newobject()是一个很强的引用。与关键字new创建的对象关联的引用是强引用。当JVM内存空间不足时,JVM宁愿抛出OfMemoryError runtime error(OOM),使程序异常终止,也不愿通过任意回收具有强引用的“活动”对象来解决内存不足的问题。对于普通对象,如果没有其他引用关系,只要它超出引用的范围或显式地将相应的(强)引用分配给null,就可以对其进行垃圾采集。具体的回收时间取决于垃圾采集策略

  软引用是一种相对较强和较弱的引用,它可以使对象免于某些垃圾采集。只有当JVM认为内存不足时,才会尝试回收软引用指向的对象。JVM确保在抛出outofmemoryerror之前清除软引用指向的对象。软引用通常用于实现内存敏感缓存。如果有空闲内存,可以临时保留缓存,并在内存不足时进行清理,以确保在使用缓存时不会耗尽内存

  特点:软参考通过软参考类实现。软参考文献的生命周期短于强参考文献。只有当JVM认为内存不足时,才会尝试回收软引用指向的对象:也就是说,JVM将确保在抛出outofmemoryerror之前清除软引用指向的对象。软引用可以与引用队列一起使用。如果软引用引用的对象被垃圾采集器回收,Java虚拟机将把软引用添加到关联的引用队列中。稍后,我们可以调用ReferenceQueue的poll()方法来检查它所关心的对象是否被回收。如果队列为空,则返回null;否则,该方法将返回队列前面的引用对象

  应用场景:软引用通常用于实现对内存敏感的缓存。如果仍有可用内存,您可以暂时保留缓存,并在内存不足时将其清除,以确保缓存在使用时不会耗尽内存

  弱引用不会免除对象的垃圾采集,但只提供了一种访问处于弱引用状态的对象的方法。这可以用于构建没有特定约束的关系。例如,维护非强制映射关系。如果试图获取对象时该对象仍然存在,请使用它,否则请重新实例化它。它也是许多缓存实现的一个选项

  弱引用是通过WeakReference类实现的。弱引用的生命周期比软引用短。当垃圾采集器线程扫描其管辖下的内存区域时,一旦找到弱引用的对象,它将回收其内存,无论当前内存空间是否足够。由于垃圾采集器是一个低优先级线程,因此不需要快速回收弱引用对象。弱引用可以与引用队列一起使用。如果弱引用引用的对象被垃圾采集,Java虚拟机将把弱引用添加到关联的引用队列中

  应用场景:弱应用程序也可用于内存敏感缓存

  幻影引用有时会转换为虚拟引用,您无法通过虚拟引用访问对象。幻影引用只提供了一种机制来确保对象在最终确定后可以执行某些操作。例如,它通常用于执行所谓的事后清理机制(post-mortem cleaning mechanism)、在我的专栏文章中介绍的Java平台的清理机制,还有一些使用幻影引用来监视对象的创建和销毁

  特点:虚拟引用也称为phantomreference,通过phantomreference类实现。无法通过虚拟引用访问对象的任何属性或函数。幻影引用只是提供了一种机制来确保对象在最终确定后执行某些操作。如果一个对象只收录虚拟引用,垃圾采集器可以随时将其回收,就像它没有引用一样。虚拟引用必须与ReferenceQueue结合使用。当垃圾采集器准备回收对象时,如果它发现它仍然有一个虚拟引用,它将在回收对象的内存之前将虚拟引用添加到关联的引用队列中

  ReferenceQueue=newreferencequeue()

  PhantomReference pr=新的PhantomReference(对象、队列)

  通过判断虚拟引用是否已添加到引用队列,程序可以知道引用对象是否将被垃圾采集。如果程序发现已将虚拟引用添加到引用队列中,它可以在回收引用对象的内存之前执行一些程序操作

  应用场景:它可以用来跟踪垃圾采集器回收的对象的活动。当垃圾采集器回收与虚拟引用关联的对象时,它将收到系统通知

  2.对象可访问性分析

  

  3.Reference

  

  

  

  所有引用类型都是抽象类java.lang.ref.reference的子类。您可能会注意到,它提供了一个get()方法:

  除了幻影引用(因为get总是返回null),如果对象没有被销毁,那么可以通过get方法获得原创对象。这意味着使用软引用和弱引用,我们可以将被访问对象重新指向强引用,即人为地改变对象的可访问性状态!这就是为什么我在上图中的一些地方画了双向箭头

  因此,对于软引用和弱引用,垃圾采集器可能存在二次确认问题,以确保处于弱引用状态的对象不会更改为强引用

  但是你认为这里可能有什么问题吗

  是的,如果我们错误地维护强引用(例如,分配给静态变量),对象可能没有机会更改回类似于弱引用的可访问性状态,从而导致内存泄漏。因此,检查弱引用指向对象是否被垃圾采集也是诊断是否存在特定内存泄漏的一种方法。如果我们的框架使用弱引用并怀疑存在内存泄漏,我们可以从这个角度进行检查

  4.ReferenceQueue

  当我们创建各种引用并将它们与相应的对象关联时,我们可以选择是否关联引用队列。JVM将在特定时间引用队列。我们可以从队列中获取相关后续逻辑的引用(remove方法实际上意味着在这里获取它)。特别是对于phantom引用,get方法只返回null。如果未指定引用队列,则它基本上没有意义。请看下面的示例代码。使用引用队列,我们可以在对象处于相应状态时执行后处理逻辑(对于phantom reference,它已完成并处于phantom Reach状态)

  

Object counter = new Object();

ReferenceQueue refQueue = new ReferenceQueue();

PhantomReference p = new PhantomReference(counter, refQueue);

counter = null;

System.gc();

try {

// Remove是一个阻塞方法,可以指定timeout,或者选择一直阻塞

Reference ref = refQueue.remove(1000L);

if (ref != null) {

// do something

}

} catch (InterruptedException e) {

// Handle it

}

  5.显式影响软引用垃圾采集

  软引用通常在最后一次引用之后保留一段时间。默认值是基于剩余堆空间(以M字节为单位)计算的。来自Java1.3.1首先,提供了-XX:softreflrupolicymspermb参数。我们可以在毫秒内设置它。例如,以下示例设置为3秒(3000毫秒)

  -XX:SoftRefLRUPolicyMSPerMB=3000

  事实上,剩余空间将受到不同JVM模式的影响。对于客户端模式,如通常的windows 32位JDK,剩余空间用于计算当前堆中的可用大小,因此更倾向于循环使用;对于服务器模式JVM,它是根据-Xmx指定的最大值计算的

  本质上,这种行为仍然是一个黑盒,具体取决于JVM实现。即使上述参数在新版本的JDK上也可能无效。此外,客户端模式下的JDK已逐渐退出历史舞台。因此,当我们应用时,我们可以参考类似的设置,但不要太依赖它

  6.diagnose JVM引用

  如果您怀疑应用程序存在由引用(或finalize)引起的回收问题,那么有许多工具或选项可供选择。例如,hotspot JVM本身提供了一个清晰的选项(printreferencegc)来获取相关信息

  注意:JDK 9广泛地重构JVM和垃圾采集日志。Printgctimestamps和printreferencegc不再存在。我将在本专栏后面的垃圾采集主题中更系统地解释它们

  7.Reachability篱笆

  可以达到强参考的效果

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线