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(); // 强引用 当内存空间 ...
随机推荐
- Presto 函数开发
0. 写在前面 Presto Functions 并不能像 Hive UDF 一样动态加载,需要根据 Function 的类型,实现 Presto 内部定义的不同接口,在 Presto 服务启动时进行 ...
- vue学习(六) 事件修饰符 stop prevent capture self once
//html <div id="app"> <div @click="divHandler" style="height:150px ...
- Python环境那点儿事(Windows篇)
Python环境配置那点儿事(Windows篇) 版本选择 (根据你的开发经验选择合适版) 适当版2.7 适当版3.6 适当版3.7 下载链接:python.org 安装 正规的Windows10操作 ...
- C#winform将dll封装到exe当中
我们在在winform程序时经常会用到外部dll,正常情况下,我的exe运行文件旁就需要这些dll文件相伴,总感觉不爽~~特别是要把软件给别人的时候,如果DLL比较多或者没有放在同一个地方,那麻烦大了 ...
- minSdkVersion、targetSdkVersion、compileSdkVersion三者的作用解析
1. minSdkVersion minSdkVersion限制安装application所需要的系统最低版本,低于该版本的系统都不可以安装该application.同时不能使用该level版本SDK ...
- scrapyd 部署
步骤 1 pip install scrapyd pip install scrapy-client 步骤 2 修改 scrapy.cfg [deploy:targetName]url = http: ...
- Python列表函数和方法
Python列表函数和方法: 函数: len(列表名): 返回列表长度 # len(列表名): # 返回列表长度 lst = [1,2,3,'a','b','c'] print("lst 列 ...
- PHP date_sunset() 函数
------------恢复内容开始------------ 实例 返回葡萄牙里斯本今天的日落时间: <?php// Lisbon, Portugal:// Latitude: 38.4 Nor ...
- mysql安装和配置详解以及Navicat连接失败问题
好久没安装过MySQL了,今天安装了下竟然碰壁了, 就来做个笔记吧.安装步骤如下: 记住:一定要看到最后!!!!!!!!! 一. 安装 1.安装 (https://dev.mysql.com/dow ...
- electron开发 - mac关闭和隐藏窗口
针对mac平台的app let willQuitApp = false; // 控制退出方式 mainWindow.on('close', (e) => { if (willQuitApp) { ...