Java引用类型之弱引用与幻像引用
这一篇将介绍弱引用和幻像引用。
1、WeakReference
WeakReference也就是弱引用,弱引用和软引用类似,它是用来描述"非必须"的对象的,它的强度比软引用要更弱一些。被弱引用关联的对象只能生存到下一次垃圾收集发生之前,简言之就是:一旦发生GC必定回收被弱引用关联的对象,不管当前的内存是否足够。WeakReference类的定义如下:
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
WeakReference继承了Reference。在ReferenceProcessorStats ReferenceProcessor::process_discovered_references()方法中调用process_discovered_reflist()方法处理弱引用,如下:
// Weak references
size_t weak_count = 0;
{
// 传递的clear_referent的值为true
weak_count = process_discovered_reflist(_discoveredWeakRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
调用的process_discovered_reflist()方法中会用后2个阶段处理弱引用,在之前已经介绍过,这里不再介绍。
2、PhantomReference
PhantomReference也就是幻像引用,它是所有引用类型中最弱的一种。一个对象是否关联到虚引用,完全不会影响该对象的生命周期,也无法通过虚引用来获取一个对象的实例。为对象设置一个虚引用的唯一目的是:能在此对象被垃圾收集器回收的时候收到一个系统通知。PhantomReference类的定义如下:
public class PhantomReference<T> extends Reference<T> {
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
可以看到幻像引用的get()方法永远返回null,所以也就无法通过虚引用来获取一个对象的实例。
public static void demo() throws InterruptedException {
Object obj = new Object();
ReferenceQueue<Object> refQueue =new ReferenceQueue<>();
PhantomReference<Object> phanRef =new PhantomReference<>(obj, refQueue);
Object objg = phanRef.get();
// 这里拿到的是null
System.out.println(objg);
// 让obj变成垃圾
obj=null;
System.gc();
Thread.sleep(3000);
// GC后会将phanRef加入到refQueue中
Reference<? extends Object> phanRefP = refQueue.remove();
//这里输出true
System.out.println(phanRefP==phanRef);
}
从以上代码中可以看到,幻像引用能够在指向对象不可达时得到一个“通知”(其实所有继承Reference的类都有这个功能),需要注意的是GC完成后,phanRef.referent依然指向之前创建Object,也就是说Object对象一直没被回收!
而造成这一现象的原因在之前也介绍过: 对于Finalreference和Phantomreference来说,clear_referent 字段传入的值为false,意味着被这两种引用类型引用的对象,如果没有其他额外处理,在GC中是不会被回收的。
对于幻像引用来说,从refQueue.remove()得到引用对象后,可以调用clear()方法强行解除引用和对象之间的关系,使得对象下次可以GC时可以被回收掉。
在ReferenceProcessor::process_discovered_references()方法中调用process_discovered_reflist()方法处理幻像引用,如下:
// Phantom references
size_t phantom_count = 0;
{
// 传递的clear_referent的值为false
phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
is_alive, keep_alive, complete_gc, task_executor);
}
调用的process_discovered_reflist()方法中会用后2个阶段处理幻像引用,在之前已经介绍过,这里不再介绍。
3、Cleaner
PhantomReference有两个比较常用的子类,如下:
(1)java.lang.ref.Cleaner:开发者用于在引用对象回收的时候触发一个动作,在JDK 9中将完全替代Object.finalize()方法。
(2)jdk.internal.ref.Cleaner:用于DirectByteBuffer对象回收的时候对于堆外内存的回收。ReferenceHandler线程会对pending链表中的jdk.internal.ref.Cleaner类型引用对象调用其clean()方法。
对于java.lang.ref.Cleaner类来说,举个例子如下:
import java.lang.ref.Cleaner;
public class CleaningExample implements AutoCloseable {
// A cleaner, preferably one shared within a library
private static final Cleaner cleaner = Cleaner.create();
static class State implements Runnable {
State() {
System.out.println("init");// initialize State needed for cleaning action
}
public void run() {
System.out.println("clean");// cleanup action accessing State, executed at most once
}
}
private final State state;
private final Cleaner.Cleanable cleanable;
public CleaningExample() {
this.state = new State();
this.cleanable = cleaner.register(this, state);
}
public void close() {
cleanable.clean();
}
public static void main(String[] args) {
while(true) {
new CleaningExample();
}
}
}
本例中每次创建对象时,都会打印init;回收对象时,都会打印clean。
下面介绍jdk.internal.ref.Cleaner类。
Cleaner继承自Java四大引用类型之一的幻像引用PhantomReference(众所周知,无法通过幻像引用获取与之关联的对象实例,且当对象仅被幻像引用引用时,在任何发生GC的时候,其均可被回收),通常PhantomReference与引用队列ReferenceQueue结合使用,可以实现幻像引用关联对象被垃圾回收时能够进行系统通知、资源清理等功能。如下图所示,当某个被Cleaner引用的对象将被回收时,JVM垃圾收集器会将此对象的引用放入到对象引用中的pending链表中,等待ReferenceHandler进行相关处理。其中,ReferenceHandler为一个拥有最高优先级的守护线程,会循环不断的处理pending链表中的对象引用,执行Cleaner的clean()方法进行相关清理工作,这在之前介绍ReferenceHandler类时介绍过,这里不再介绍。

Cleaner只有在清理逻辑足够轻量和直接的时候才适合使用Cleaner,繁琐耗时的清理逻辑将有可能导致ReferenceHandler线程阻塞从而耽误其它的清理任务。
相关文章的链接如下:
1、在Ubuntu 16.04上编译OpenJDK8的源代码
13、类加载器
14、类的双亲委派机制
15、核心类的预装载
16、Java主类的装载
17、触发类的装载
18、类文件介绍
19、文件流
20、解析Class文件
21、常量池解析(1)
22、常量池解析(2)
23、字段解析(1)
24、字段解析之伪共享(2)
25、字段解析(3)
28、方法解析
29、klassVtable与klassItable类的介绍
30、计算vtable的大小
31、计算itable的大小
32、解析Class文件之创建InstanceKlass对象
33、字段解析之字段注入
34、类的连接
35、类的连接之验证
36、类的连接之重写(1)
37、类的连接之重写(2)
38、方法的连接
39、初始化vtable
40、初始化itable
41、类的初始化
42、对象的创建
43、Java引用类型
作者持续维护的个人博客 classloading.com。
关注公众号,有HotSpot源码剖析系列文章!
参考文章:
Java引用类型之弱引用与幻像引用的更多相关文章
- 你不可不知的Java引用类型之——弱引用
定义 弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型.在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收. 说明 弱 ...
- Java引用类型之软引用(2)
下面接着上一篇介绍第2阶段和第3阶段的处理逻辑. 2.process_phase2() 第2个阶段移除所有的referent还存活的Reference,也就是从refs_list中移除Referenc ...
- Java引用类型之最终引用
FinalReference类只有一个子类Finalizer,并且Finalizer由关键字final修饰,所以无法继承扩展.类的定义如下: class FinalReference<T> ...
- Java的四种引用类型之弱引用
先说结论: 首先,Java中有四种引用类型:强引用.软引用.弱引用.虚引用.-- 在 Java 1.2 中添加的,见 package java.lang.ref; . 其次,这几个概念是与垃圾回收有关 ...
- Java中的四种引用类型,强引用,软引用,弱引用,虚引用
对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用 2软引用 3弱引用 ...
- java强引用、软引用、弱引用、虚引用
前言概述 在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象.这就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走 ...
- 【转载】 Java 7之基础 - 强引用、弱引用、软引用、虚引用
原文地址:http://blog.csdn.net/mazhimazh/article/details/19752475 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一 ...
- Java 7之基础 - 强引用、弱引用、软引用、虚引用
1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内 ...
- Java 的强引用、弱引用、软引用、虚引用
1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内存空间 ...
随机推荐
- 题解 洛谷 P5331 【[SNOI2019]通信】
考虑用费用流解决本题. 每个哨站看作一个点,并将其拆为两个点,建图方式为: \(S \longrightarrow x_i\) 容量为\(1\),费用为\(0\) \(x_i \longrightar ...
- APP自动化 -- swipe(滑动屏幕)
- springMVC(二)springMVC、Mybatis、spring整合
数据库设置: 一.配置文件设置 (1).springMVC配置文件(前端控制器web.xml,核心配置文件springmvc.xml) <?xml version="1.0" ...
- 一文了解JDK12 13 14 GC调优秘籍-附PDF下载
目录 简介 那些好用的VM参数 G1的变化 配置FlightRecorder RAM参数 JDK13中的ZGC RTM支持 总结 简介 想了解JDK12,13,14中的GC调优秘籍吗?想知道这三个版本 ...
- 深度学习中损失值(loss值)为nan(以tensorflow为例)
我做的是一个识别验证码的深度学习模型,识别的图片如下 验证码图片识别4个数字,数字间是有顺序的,设立标签时设计了四个onehot向量链接起来,成了一个长度为40的向量,然后模型的输入也是40维向量用s ...
- Python2.7 PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 问题解决
# 报错信息 PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.insta ...
- 我是如何从零开始自学转行IT并进入世界500强实现薪资翻倍?
本部分内容对应视频链接. 熟悉我的朋友应该知道,我本科及硕士期间所学的专业都是机械相关,毕业两年之后才从零开始自学转行成为一名程序员.当时我写了一篇文章,介绍我的转行经历,很多小伙伴因为我的这篇文章, ...
- jieba尝鲜
import jieba strings = '我工作在安徽的安徽师范大学,这个大学很美丽,在芜湖' # print(dir(jieba)) dic_strings = {} lst_strings ...
- Python time strftime()方法
描述 Python time strftime() 函数接收以时间元组,并返回以可读字符串表示的当地时间,格式由参数format决定.高佣联盟 www.cgewang.com 语法 strftime( ...
- PHP date_time_set() 函数
------------恢复内容开始------------ 实例 设置时间: <?php$date=date_create("2013-05-01");date_time_ ...