Reference SoftReference WeakReference PhantomReference Cleaner 的研究与实践
最近在看netty的时候看到直接内存的相关概念,为了更详细的了解一下具体原理,搜到了一篇不错的文章 http://lovestblog.cn/blog/2015/05/12/direct-buffer/
因为文章中又涉及到PhantomReference的概念,又为了更详细的了解一下具体原理,又搜到了另一篇不错的文章 https://blog.csdn.net/xlinsist/article/details/57089288
这些概念很多文章中都有讲解,下面主要是针对各个Reference的具体实践(体现在最后的代码部分,各个实验都有相关注释,实验环境及所列源码均为jdk1.8.0_172)
Reference抽象类有两个构造方法,referent是必须参数,queue可选
Reference被类加载器加载初始化后会启动一个后台线程,这个线程的作用是将jvm传给它的Reference们加入到它们自己的queue中
新标签页查看大图
加入queue的Reference就可以被持有queue的对象进行相应的逻辑处理了,例如WeakHashMap会把不新鲜的对象给清除掉
Cleaner与DirectByteBuffer的部分源码
下面是根据各个Reference的定义做的一些具体实验(实验结果表明,Weak和Cleaner一遇到gc同时只剩下它们引用它们的referent的时候,这些referent一定会被清除掉)
实验记得加上main注释上的启动参数
package xyz.fz.test; import sun.misc.Cleaner; import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference; public class ReferenceTest { private static final int MB = 1024 * 1024; private static ReferenceQueue<Object> queue = new ReferenceQueue<>(); private static class BigBaby {
// just hold memory
private byte[] weight = new byte[20 * MB]; BigBaby() {
}
} private static class MyCleanerRunner implements Runnable {
private String somethingYouWant; MyCleanerRunner(String something) {
this.somethingYouWant = something;
} @Override
public void run() {
System.out.println(somethingYouWant);
}
} // -Xms64M -Xmx64M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps
public static void main(String[] args) {
System.out.println("============= softReferenceBigBabyGcNotWork =============");
System.gc();
softReferenceBigBabyGcNotWork();
System.out.println("============= softReferenceBigBabyGc =============");
System.gc();
softReferenceBigBabyGc();
System.out.println("============= weakReferenceBigBabyGc =============");
System.gc();
weakReferenceBigBabyGc();
System.out.println("============= phantomReferenceBigBabyGc =============");
System.gc();
phantomReferenceBigBabyGc();
System.out.println("============= cleanerBigBabyGc =============");
System.gc();
cleanerBigBabyGc();
System.out.println("============= queueFifoTest =============");
System.gc();
queueFifoTest();
} private static void softReferenceBigBabyGcNotWork() {
// 内存充足
// 软持有对象置空
// 主动gc
// 软持有对象没有被清除
BigBaby bigBaby = new BigBaby();
SoftReference<BigBaby> softReference = new SoftReference<>(bigBaby, queue);
bigBaby = null;
gcAndWait();
System.out.println("SoftReference's Referent: " + softReference.get());
printQueue();
} private static void softReferenceBigBabyGc() {
// 内存充足
// 软持有对象置空
// 创建新对象(导致内存不足)
// 主动(或被动)gc
// 软持有对象被清除,该软引用加入引用队列
BigBaby bigBaby = new BigBaby();
SoftReference<BigBaby> softReference = new SoftReference<>(bigBaby, queue);
bigBaby = null;
BigBaby bigBaby2 = new BigBaby();
BigBaby bigBaby3 = new BigBaby();
gcAndWait();
System.out.println("SoftReference's Referent: " + softReference.get());
printQueue();
} private static void weakReferenceBigBabyGc() {
// 内存充足
// 弱持有对象置空
// 主动gc
// 弱持有对象被清除,弱引用加入引用队列
BigBaby bigBaby = new BigBaby();
WeakReference<BigBaby> weakReference = new WeakReference<>(bigBaby, queue);
bigBaby = null;
gcAndWait();
System.out.println("WeakReference's Referent: " + weakReference.get());
printQueue();
} private static void phantomReferenceBigBabyGc() {
// 内存充足
// 幻持有对象置空
// 主动gc
// 幻持有对象没有被清除(内存充足的原因?),幻引用加入引用队列
BigBaby bigBaby = new BigBaby();
PhantomReference<BigBaby> phantomReference = new PhantomReference<>(bigBaby, queue);
bigBaby = null;
gcAndWait();
printQueue();
} private static void cleanerBigBabyGc() {
// 内存充足
// Cleaner持有对象置空
// 主动gc
// Cleaner持有对象被清除,Cleaner的runner被执行 /*
Cleaner是一个特殊的幻引用,
虽然它的构造中也有引用队列,但这个引用队列是个假引用队列,因为它从来不会被使用,仅仅作为幻引用的必要参数而已,
真正使用的是其定义的runner,
在持有对象被清除后runner得到执行
*/ /*
DirectByteBuffer用于分配堆外内存,
其中就有一个属性为cleaner,
并且该cleaner的持有对象就是其自身(DirectByteBuffer),
也就是说当这个DirectByteBuffer被gc回收之后,
cleaner中的runner方法将得到执行(对堆外内存进行回收)
*/
BigBaby bigBaby = new BigBaby();
Cleaner cleaner = Cleaner.create(bigBaby, new MyCleanerRunner("I'm Cleaner's runner. I can do what you want to do."));
bigBaby = null;
gcAndWait();
} private static void queueFifoTest() {
/*
从queue的名字会误认为是先进先出的队列,但是从实现和实验中可以看出他其实是后进先出
*/
BigBaby bigBaby = new BigBaby();
WeakReference<BigBaby> weakReference = new WeakReference<>(bigBaby, queue);
System.out.println(weakReference);
bigBaby = null;
gcAndWait(); bigBaby = new BigBaby();
WeakReference<BigBaby> weakReference2 = new WeakReference<>(bigBaby, queue);
System.out.println(weakReference2);
bigBaby = null;
gcAndWait(); bigBaby = new BigBaby();
WeakReference<BigBaby> weakReference3 = new WeakReference<>(bigBaby, queue);
System.out.println(weakReference3);
bigBaby = null;
gcAndWait(); printQueue();
} private static void printQueue() {
Object o;
int size = 0;
while ((o = queue.poll()) != null) {
System.out.println("Reference: " + o);
size++;
}
System.out.println("Reference Queue Size: " + size);
} private static void gcAndWait() {
System.gc();
try {
System.out.println("gc waiting ...");
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果如下:
============= softReferenceBigBabyGcNotWork =============
2018-07-18T17:24:34.874+0800: 0.239: [GC (System.gc()) [PSYoungGen: 3994K->1112K(18944K)] 3994K->1120K(62976K), 0.0012344 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:34.876+0800: 0.240: [Full GC (System.gc()) [PSYoungGen: 1112K->0K(18944K)] [ParOldGen: 8K->1015K(44032K)] 1120K->1015K(62976K), [Metaspace: 3467K->3467K(1056768K)], 0.0048045 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:34.890+0800: 0.255: [GC (System.gc()) [PSYoungGen: 327K->96K(18944K)] 21823K->21591K(62976K), 0.0004161 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:34.891+0800: 0.255: [Full GC (System.gc()) [PSYoungGen: 96K->0K(18944K)] [ParOldGen: 21495K->21389K(44032K)] 21591K->21389K(62976K), [Metaspace: 3469K->3469K(1056768K)], 0.0098622 secs] [Times: user=0.03 sys=0.02, real=0.01 secs]
gc waiting ...
SoftReference's Referent: xyz.fz.test.ReferenceTest$BigBaby@3b07d329
Reference Queue Size: 0
============= softReferenceBigBabyGc =============
2018-07-18T17:24:35.901+0800: 1.266: [GC (System.gc()) [PSYoungGen: 655K->64K(18944K)] 22045K->21453K(62976K), 0.0006612 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:35.902+0800: 1.267: [Full GC (System.gc()) [PSYoungGen: 64K->0K(18944K)] [ParOldGen: 21389K->900K(44032K)] 21453K->900K(62976K), [Metaspace: 3470K->3470K(1056768K)], 0.0119403 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
2018-07-18T17:24:35.927+0800: 1.292: [GC (Allocation Failure) [PSYoungGen: 0K->32K(18944K)] 41860K->41892K(62976K), 0.0012161 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:35.928+0800: 1.293: [Full GC (Ergonomics) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 41860K->41860K(44032K)] 41892K->41860K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0043798 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:35.933+0800: 1.297: [GC (Allocation Failure) [PSYoungGen: 0K->0K(18944K)] 41860K->41860K(62976K), 0.0006057 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:35.933+0800: 1.298: [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(18944K)] [ParOldGen: 41860K->21362K(44032K)] 41860K->21362K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0130772 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
2018-07-18T17:24:35.948+0800: 1.313: [GC (System.gc()) [PSYoungGen: 0K->0K(18944K)] 41842K->41842K(62976K), 0.0005524 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:35.949+0800: 1.313: [Full GC (System.gc()) [PSYoungGen: 0K->0K(18944K)] [ParOldGen: 41842K->41842K(44032K)] 41842K->41842K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0023415 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
gc waiting ...
SoftReference's Referent: null
Reference: java.lang.ref.SoftReference@41629346
Reference Queue Size: 1
============= weakReferenceBigBabyGc =============
2018-07-18T17:24:36.951+0800: 2.316: [GC (System.gc()) [PSYoungGen: 327K->32K(18944K)] 42170K->41874K(62976K), 0.0007930 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:36.952+0800: 2.317: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 41842K->882K(44032K)] 41874K->882K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0072817 secs] [Times: user=0.00 sys=0.02, real=0.01 secs]
2018-07-18T17:24:36.962+0800: 2.326: [GC (System.gc()) [PSYoungGen: 327K->64K(18944K)] 21690K->21426K(62976K), 0.0004395 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:36.962+0800: 2.327: [Full GC (System.gc()) [PSYoungGen: 64K->0K(18944K)] [ParOldGen: 21362K->883K(44032K)] 21426K->883K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0074164 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
gc waiting ...
WeakReference's Referent: null
Reference: java.lang.ref.WeakReference@404b9385
Reference Queue Size: 1
============= phantomReferenceBigBabyGc =============
2018-07-18T17:24:37.970+0800: 3.335: [GC (System.gc()) [PSYoungGen: 327K->64K(18944K)] 1210K->947K(62976K), 0.0004446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:37.971+0800: 3.335: [Full GC (System.gc()) [PSYoungGen: 64K->0K(18944K)] [ParOldGen: 883K->883K(44032K)] 947K->883K(62976K), [Metaspace: 3471K->3471K(1056768K)], 0.0077789 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2018-07-18T17:24:37.981+0800: 3.346: [GC (System.gc()) [PSYoungGen: 327K->96K(18944K)] 21691K->21459K(62976K), 0.0004417 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:37.981+0800: 3.346: [Full GC (System.gc()) [PSYoungGen: 96K->0K(18944K)] [ParOldGen: 21363K->21363K(44032K)] 21459K->21363K(62976K), [Metaspace: 3472K->3472K(1056768K)], 0.0042990 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
gc waiting ...
Reference: java.lang.ref.PhantomReference@6d311334
Reference Queue Size: 1
============= cleanerBigBabyGc =============
2018-07-18T17:24:38.986+0800: 4.351: [GC (System.gc()) [PSYoungGen: 327K->32K(18944K)] 21691K->21395K(62976K), 0.0004979 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:38.987+0800: 4.351: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 21363K->883K(44032K)] 21395K->883K(62976K), [Metaspace: 3472K->3472K(1056768K)], 0.0077382 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2018-07-18T17:24:38.998+0800: 4.363: [GC (System.gc()) [PSYoungGen: 327K->160K(18944K)] 21691K->21523K(62976K), 0.0005646 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:38.999+0800: 4.364: [Full GC (System.gc()) [PSYoungGen: 160K->0K(18944K)] [ParOldGen: 21363K->884K(44032K)] 21523K->884K(62976K), [Metaspace: 3482K->3482K(1056768K)], 0.0077882 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
gc waiting ...
I'm Cleaner's runner. I can do what you want to do.
============= queueFifoTest =============
2018-07-18T17:24:40.007+0800: 5.372: [GC (System.gc()) [PSYoungGen: 655K->32K(18944K)] 1540K->924K(62976K), 0.0004796 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:40.008+0800: 5.372: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 892K->884K(44032K)] 924K->884K(62976K), [Metaspace: 3487K->3487K(1056768K)], 0.0079891 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
java.lang.ref.WeakReference@682a0b20
2018-07-18T17:24:40.018+0800: 5.383: [GC (System.gc()) [PSYoungGen: 327K->32K(18944K)] 21692K->21396K(62976K), 0.0005765 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:40.019+0800: 5.383: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 21364K->884K(44032K)] 21396K->884K(62976K), [Metaspace: 3487K->3487K(1056768K)], 0.0080978 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
gc waiting ...
java.lang.ref.WeakReference@3d075dc0
2018-07-18T17:24:41.029+0800: 6.394: [GC (System.gc()) [PSYoungGen: 327K->32K(18944K)] 21692K->21396K(62976K), 0.0006605 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2018-07-18T17:24:41.030+0800: 6.395: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 21364K->884K(44032K)] 21396K->884K(62976K), [Metaspace: 3487K->3487K(1056768K)], 0.0083753 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
gc waiting ...
java.lang.ref.WeakReference@214c265e
2018-07-18T17:24:42.041+0800: 7.406: [GC (System.gc()) [PSYoungGen: 327K->32K(18944K)] 21692K->21396K(62976K), 0.0006599 secs] [Times: user=0.00 sys=0.02, real=0.00 secs]
2018-07-18T17:24:42.042+0800: 7.407: [Full GC (System.gc()) [PSYoungGen: 32K->0K(18944K)] [ParOldGen: 21364K->884K(44032K)] 21396K->884K(62976K), [Metaspace: 3487K->3487K(1056768K)], 0.0102298 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
gc waiting ...
Reference: java.lang.ref.WeakReference@214c265e
Reference: java.lang.ref.WeakReference@3d075dc0
Reference: java.lang.ref.WeakReference@682a0b20
Reference Queue Size: 3
Heap
PSYoungGen total 18944K, used 655K [0x00000000feb00000, 0x0000000100000000, 0x0000000100000000)
eden space 16384K, 4% used [0x00000000feb00000,0x00000000feba3f90,0x00000000ffb00000)
from space 2560K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)
to space 2560K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)
ParOldGen total 44032K, used 884K [0x00000000fc000000, 0x00000000feb00000, 0x00000000feb00000)
object space 44032K, 2% used [0x00000000fc000000,0x00000000fc0dd328,0x00000000feb00000)
Metaspace used 3494K, capacity 4564K, committed 4864K, reserved 1056768K
class space used 377K, capacity 388K, committed 512K, reserved 1048576K
Reference SoftReference WeakReference PhantomReference Cleaner 的研究与实践的更多相关文章
- Java之引用类型分析(SoftReference/WeakReference/PhantomReference)
引言: 即使对于Java的很多老鸟来说,如果忽然问他引用的类型,大概率是一脸茫然,不知所措的-.Java中的引用还分类型,神马情况??? 本文将针对这些类型进行分析,帮助您一文知所有类型. Java的 ...
- 4种引用与垃圾回收 :StrongReference, SoftReference, WeakReference , PhantomReference
- Java核心技术-高级特性(2)- SoftReference, WeakReference and PhantomReference
Java.lang.ref 是 Java 类库中比较特殊的一个包,它提供了与 Java 垃圾回收器密切相关的引用类.这些引用类对象可以指向其它对象,但它们不同于一般的引用,因为它们的存在并不防碍 Ja ...
- java SoftReference WeakReference
Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中.这些类还提供了与垃圾收集器(garbage collector)之间有限的交互. 1.先“ ...
- 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践
提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...
- Java中引用类 strong reference .SoftReference 、 WeakReference 和 PhantomReference的区别
当在 Java 2 平台中首次引入 java.lang.ref 包,其中包含 SoftReference . WeakReference 和 PhantomReference 三个引用类,引用类的 ...
- Softreference | WeakReference
转自:http://blog.csdn.net/kavendb/article/details/5935577 本文介绍对象的强.软.弱和虚引用的概念.应用及其在UML中的表示. 1.对象的强.软.弱 ...
- CSS技能汇总,研究及实践
最近一直在研究CSS,因为发现实践中大部分时间都在写CSS,且自己感觉写的很烂,虽然以前看的很多,但却很少有去实践过,更别提研究了,现在发现根本就不是你懂你就会,很多都是你用着用着才真的会了的,于是现 ...
- Redis集群研究和实践(基于redis 3.0.5)
前言 redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用.现在的2.x的稳定版本是2.8.19,也是我们项目中普遍用到的版本. redis在年初发布了3.0. ...
随机推荐
- 原生tab选项卡制作
html部分 <div class="tab"> <div class="nav"> <ul> <li class=& ...
- ubuntu 常见命令整理
SSH 查看ssh服务的进程是否已经开启ps -e | grep ssh 安装ssh服务组件sudo apt-get install openssh-server 服务启动和关闭 方法1:servic ...
- strcpy和memcpy,memmove函数的区别
strcpy和memcpy的区别 strcpy和memcpy都是标准C库函数,它们有下面的特点. strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制 ...
- Zookeeper注册中心概述
Zookeeper介绍(配合Dubbox使用) 官方推荐使用zookeeoer注册中心,注册中心负责服务地址的注册和查找,相当于目录服务,提供提供者和消费者只在启动时与注册中心交互,注册中心不转发请求 ...
- H5+JS生成验证码
效果图如下: <canvas id="canvas1" style="margin-left: 200px;"></canvas>< ...
- opencv学习之路(11)、图像几何变换
一.图像缩放 #include<opencv2/opencv.hpp> using namespace cv; void main(){ Mat src=imread("E:// ...
- tar+nc传输文件的使用
- Python标准库inspect
inspect模块用于收集python对象的信息,可以获取类或函数的参数的信息,源码,解析堆栈,对对象进行类型检查等等,有几个好用的方法: getargspec(func) 返回一个命名元组ArgSp ...
- Ant build.xml详解
Ant的概念 可能有些读者并不连接什么是Ant以及入可使用它,但只要使用通过Linux系统得读者,应该知道make这个命令.当编译Linux内核及一些软件的源程序时,经常要用这个命令.Make命令其实 ...
- topcoder srm 693 div1 -3
1.给出一个$n$个顶点的无向带权图.其中顶点$i,i+1$之间存在边,$i,i+2$之间存在边.而且仅有这些边.现在删掉其中的一些边,剩下的边满足图仍然是2联通的情况下使得权值和最小? 思路:其实就 ...