finalize()和四种引用的一点思考
一次对ThreadLocal的学习引发的思考
ThreadLocal对Entry的引用是弱引用,于是联想到四种引用的生命周期。
- 强引用,不会进行垃圾回收
- 软引用,JVM内存不够,进行回收
- 弱引用,下次GC,直接进行回收
- 虚引用,不会对GC产生任何影响,结合ReferenceQueue使用,只为引用被回收时收到通知。
所以如果只有弱引用指向ThreadLocal,那么下次GC,ThreadLocal将被回收。阿里的代码规范上也要求ThreadLocal要被static修饰,就是为了防止后续还要使用,但ThreadLocal已被GC回收。
然后为了测试弱引用被GC写了下面的代码:
@Test
public void test() throws InterruptedException {
ReferenceQueue queue = new ReferenceQueue();
Thread thread = new Thread(() -> {
while (true){
Object obj;
if((obj = queue.poll())!= null){
System.out.println("queue!!! " + obj);
}
}
});
thread.start();
Reference reference1 = new Reference();
WeakReference reference = new WeakReference(reference1, queue);
System.out.println(reference);
reference1 = null;
System.gc();
thread.join();
}
private static class Reference {
@Override
protected void finalize() throws Throwable {
System.out.println("finalize!!!"+this);
}
}
输出如下:
java.lang.ref.WeakReference@200a570f
queue!!! java.lang.ref.WeakReference@200a570f
finalize!!!ConnectionTest$Reference@74560fd0
queue比finalize先输出,开始我以为是io竞争,忽视不理,将弱引用改为虚引用,这时输出为:
java.lang.ref.PhantomReference@200a570f
finalize!!!ConnectionTest$Reference@74560fd0
queue一直不输出,这时我怀疑是我代码问题,于是在网上百度了别人的例子改了下,可以正常输出queue,我又怀疑是我自定义类的问题,于是将原来代码虚引用改为String
PhantomReference reference = new PhantomReference(new String(), queue);
正常输出,what???但是我的自定义类没什么东西啊,只有一个finalize(),难道它会影响引用,但弱引用没问题,虚引用就有问题???于是我将虚引用改为软引用,然后创建大量的数组,正常输出。
于是我怀疑finalize对虚引用有什么影响,难道找到bug了,我百度了finalize和虚引用,然后找到以下文章:
JAVA虚引用为什么在重载finalize后不会在回收时被置入引用队列?
finalize方法执行过程
详细可以看:How to Handle Java Finalization's Memory-Retention Issues
- 重写了finalize()的类实例化时,JVM会标记该对象为finalizable
- GC thread检测到对象不可达时,如果对象是finalizable,会将对象添加到finalization queue,对象重新可达,推迟GC
- finalizer thread在一段时间之后,将会从finalization queue出队对象,调用对象的finalize(),随后标记对象为finalized
- GC thread重新检测到对象不可达,这时才回收对象。
看到这也就明白的虚引用在重写了finalize()之后为啥不输出queue,要经过两次GC,对象才会被回收,这时才进入Reference Queue,将代码改动如下:
@Test
public void test5() throws InterruptedException {
Reference reference = new Reference();
ReferenceQueue referenceQueue = new ReferenceQueue();
Thread thread = new Thread(() -> {
while (true){
Object obj;
if((obj = referenceQueue.poll())!= null){
System.out.println("queue!!! "+obj);
}
}
});
thread.start();
PhantomReference reference1 = new PhantomReference(reference, referenceQueue);
reference = null;
System.gc();
Thread.sleep(1000);
System.gc();
thread.join();
}
输出如下:
finalize!!!ConnectionTest$Reference@74560fd0
queue!!! java.lang.ref.PhantomReference@5b708109
jstat也可以看到进行了两次的GC差别:
不输出queue的gc情况:
输出queue的gc情况:
虚引用和弱引用进入Reference Queue时机
上面已经解释了虚引用为啥不输出queue的原因,但为啥弱引用只经过一次gc就输出了queue的??
JAVA虚引用为什么在重载finalize后不会在回收时被置入引用队列?
这两篇文章提到:
- 弱引用:一旦对象只有弱引用,GC是会把弱引用直接插入引用队列,与插入finalization queue是同一时机。
- 虚引用:要在对象正式被回收,才进入引用队列
此外,我还发现jdk8虚引用不用调用clear()清除referent对象,要在引用队列中手动清除。
jdk8 PhantomReference注释如下:
* Unlike soft and weak references, phantom references are not
* automatically cleared by the garbage collector as they are enqueued. An
* object that is reachable via phantom references will remain so until all
* such references are cleared or themselves become unreachable.
finalize()和四种引用的一点思考的更多相关文章
- Java虚拟机15:再谈四种引用状态
JVM的四种引用状态 在Java虚拟机5:Java垃圾回收(GC)机制详解一文中,有简单提到过JVM的四种引用状态,当时只是简单学习,知道有这么一个概念,对四种引用状态理解不深.这两天重看虚拟机这部分 ...
- Java中的四种引用
引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...
- Java虚拟机19:再谈四种引用状态
JVM的四种引用状态 在Java虚拟机5:Java垃圾回收(GC)机制详解一文中,有简单提到过JVM的四种引用状态,当时只是简单学习,知道有这么一个概念,对四种引用状态理解不深.这两天重看虚拟机这部分 ...
- JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例
简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...
- java四种引用及在LeakCanery中应用
java 四种引用 Java4种引用的级别由高到低依次为: StrongReference > SoftReference > WeakReference > PhantomRefe ...
- JAVA四种引用方式
JAVA四种引用方式: java.lang.ref: 强引用(直接变量赋值) 软引用(SoftReference): 只有在要发生OOM错误之前才会回收掉老的软引用对象,应用场景主要防止内存溢出.(缓 ...
- JAVA不可不知的强软弱虚四种引用
一个变量指向new对象,就是引用,在java中有四种引用,分别是强软弱虚,常见的Object o = new Object(),就是强引用,垃圾回收的时候,强引用不会被回收. 公用类: publi ...
- Java中四种引用:强、软、弱、虚引用
这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...
- Java四种引用包括强引用,软引用,弱引用,虚引用。
Java四种引用包括强引用,软引用,弱引用,虚引用. 强引用: 只要引用存在,垃圾回收器永远不会回收Object obj = new Object();//可直接通过obj取得对应的对象 如obj.e ...
随机推荐
- 第四模块 :微服务调用链监控CAT架构和实践
采样率:每一个请求为都进行记录,或者100次请求为记录50次 各个开源框架都满足opentracing的标准,只要使用opentracing标准埋点的客户端,可以使用不同的客户端去展示,opentra ...
- Snmp扫描-snmpwalk、snmpcheck
SNMp经常被错误配置,是信息的金矿. SNMP服务是使用明文传输的,即使不能通过community进行查询,也有可能使用抓包嗅探的方法得到SNMP数据包中的数据. snmpwalk命令可以查询到很多 ...
- ThinkPHP5使用阿里云OSS图片上传
1.下载OSS文件放在网站根目录下(OSS文件下载地址:https://gitee.com/jth1234/oss_files.git) 2.在入口文件中加载OSS 3.config文件配置oss信息 ...
- C# MVC LayUI实现下拉框二级联动
一.layui.use 1.LayUI的官方使用文档:https://www.layui.com/doc/ 2.layui的内置模块不是默认就加载好的,必须要执行启动模块的这种方法后模块才会加载: 3 ...
- RocketMQ入门到入土(一)新手也能看懂的原理和实战!
学任何技术都是两步骤: 搭建环境 helloworld 我也不例外,直接搞起来. 一.RocketMQ的安装 1.文档 官方网站 http://rocketmq.apache.org GitHub h ...
- Python实用笔记——错误处理
让我们用一个例子来看看try的机制: try: print('try...') r = 10 / 0 print('result:', r) except ZeroDivisionError as e ...
- Oracle数据库的闪回操作(查询指定时间的数据、恢复数据)
通过DELETE删除数据后相当于放入回收站,一般情况下可以找回:通过UPDATE更新数据后数据库也会保留数据快照.闪回就是恢复指定时间的数据快照以达到恢复数据的目的.根据步骤一查询出数据快照,恢复数据 ...
- GIT更换连接方式
1-使用 git remote -v 查看对应的克隆地址: git remote -v origin https://github.com/username/repository.git (fetch ...
- python 类中方法总结 --- 实例方法、类方法、静态方法
在python的类语法中,可以出现三种方法,具体如下: (1)实例方法 1)第一个参数必须是实例本身,一般使用[self]表示. 2)在实例方法中,可以通过[self]来操作实例属性,[类名]来操作类 ...
- SpringBoot2.x入门:快速创建一个SpringBoot应用
前提 这篇文章是<SpringBoot2.x入门>专辑的第2篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 常规的套路会建议使用Spring官方提 ...