WeakHashMap和Java引用类型详细解析
WeakHashMap是种弱引用的HashMap,这是说,WeakHashMap里的key值如果没有外部强引用,在垃圾回收之后,WeakHashMap的对应内容也会被移除掉。
1.1 Java的引用类型
在讲解WeakHashMap之前,我们需要了解Java中引用的相关类:
ReferenceQueue,引用队列,与某个引用类绑定,当引用死亡后,会进入这个队列。
HardReference,强引用,任何以类似String str=new String()建立起来的引用,都是强引用。在str指向另一个对象或者null之前,该String对象都不会被GC(Garbage Collector垃圾回收器)回收;
WeakReference,弱引用,可以通过java.lang.ref.WeakReference来建立,当GC要求回收对象时,它不会阻止对象被回收,该对象会立刻被回收;
SoftReference,软引用,可以通过java.lang.ref.SoftReference来建立,和弱引用一样,当GC要求回收时,它不会阻止对象被回收,但不同的是该对回收过程会被延迟,必须要等到JVM heap内存不够用,接近产生OutOfMemory错误时,才会回收;
PhantomReference,虚引用,可以通过java.lang.ref.PhantomPeference来建立,这种类型的引用很特别,大多数时间,无法通过它拿到其引用的对象,但是,当这个对象死亡的时候,该引用还是会进入ReferenceQueue队列。
下面提供一个例子来分别说明它们的作用:
|
ReferenceQueue<Ref> queue = new ReferenceQueue<Ref>(); // 创建一个弱引用 WeakReference<Ref> weak = new WeakReference<Ref>(new Ref("Weak"),queue); // 创建一个虚引用 PhantomReference<Ref> phantom = new PhantomReference<Ref>(new Ref( "Phantom"), queue); // 创建一个软引用 SoftReference<Ref> soft = new SoftReference<Ref>(new Ref("Soft"),queue); System.out.println("引用内容:"); System.out.println(weak.get()); System.out.println(phantom.get()); System.out.println(soft.get()); System.out.println("被回收的引用:"); for (Reference r = null; (r = queue.poll()) != null;) { System.out.println(r); } |
Ref这个类是个自定义的测试类,源码如下所示:
|
class Ref { Object v; Ref(Object v) { this.v = v; } public String toString() { return this.v.toString(); } } |
在这个例子里,分别创建了弱引用、虚引用和软引用,get()方法用于获取它们引用的Ref对象,可以注意到,Ref对象在外部并没有任何引用,所以,在某个时间点,GC应当会回收对象。来看看代码执行的结果:
|
引用内容: Weak null Soft 被回收的引用: |
可以看到,弱引用和软引用的对象还是可达的,但是虚引用是不可达的。被回收的引用没有内容,说明GC还没有回收它们。
这证实了虚引用的性质:
虚引用非常弱,以至于它自己也找不到自己的引用内容。
对之前的代码进行改造,在输出内容前加入代码:
|
// 强制垃圾回收 System.gc(); |
再执行一次,得到结果:
|
引用内容: null null Soft 被回收的引用: java.lang.ref.WeakReference@3b764bce java.lang.ref.PhantomReference@759ebb3d |
现在可达的引用只剩下Soft了,引用队列里多出了两条引用,说明WeakReference和PhantomReference的对象被回收。
再修改一次代码,让WeakPeference和PhantomReference去引用一个强引用对象:
|
Ref wr = new Ref("Hard"); WeakReference<Ref> weak = new WeakReference<Ref>(wr, queue); PhantomReference<Ref> phantom = new PhantomReference<Ref>(wr, queue); |
输出结果如下所示:
|
引用内容: Hard null Soft 被回收的引用: |
这证实了弱引用的性质:
弱引用的对象,如果没有被强引用,在垃圾回收后,引用对象会不可达。
1.2 WeakHashMap实现方式
WeakHashMap利用了ReferenceQueue和WeakReference来实现它的核心功能:当key值没有强引用的时候,从WeakHashMap里移除。
先来看看WeakHashMap的键值对实体类WeakHashMap.Entry的实现:
|
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) { super(key, queue); this.value = value; this.hash = hash; this.next = next; } ... } |
关键注意两处:
1、Entry继承自WeakReference;
2、Entry本身没有保存key值,而是把key作为WeakReference的引用对象交给了super构造。
这说明,Entry是个针对key值的弱引用。
WeakHashMap实现清除陈旧实体的方法是expungStaleEntries(),其源码实现如下:
|
private void expungeStaleEntries() { //遍历引用队列,找到每一个被GC收集的对象 for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); //从链表里移除该实体 Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { if (prev == e) table[i] = next; else prev.next = next; //帮助GC执行 e.value = null; size--; break; } prev = p; p = next; } } } } |
expungStaleEntries()方法会在resize、put、get、forEach方法里被调用。
WeakHashMap和Java引用类型详细解析的更多相关文章
- java容器详细解析
前言:在java开发中我们肯定会大量的使用集合,在这里我将总结常见的集合类,每个集合类的优点和缺点,以便我们能更好的使用集合.下面我用一幅图来表示 其中淡绿色的表示接口,红色的表示我们经常使用的类. ...
- java容器详细解析(转)
:在java开发中我们肯定会大量的使用集合,在这里我将总结常见的集合类,每个集合类的优点和缺点,以便我们能更好的使用集合.下面我用一幅图来表示 其中淡绿色的表示接口,红色的表示我们经常使用的类. 1: ...
- Java正则表达式详细解析
元字符 正则表达式使用一些特定的元字符来检索.匹配和替换符合规则的字符串 元字符:普通字符.标准字符.限定字符(量词).定位字符(边界字符) 正则表达式引擎 正则表达式是一个用正则符号写出来的公式 程 ...
- java类生命周期详细解析
(一)详解java类的生命周期 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前 ...
- 转:二十一、详细解析Java中抽象类和接口的区别
转:二十一.详细解析Java中抽象类和接口的区别 http://blog.csdn.net/liujun13579/article/details/7737670 在Java语言中, abstract ...
- 2019年 Java 面试题解析
2019年 Java 面试题解析 转载地址:https://www.cnblogs.com/Zz-maker/p/11193930.html 作者: Zz_maker 包含的模块: 本文分为十九个模块 ...
- java jar包解析:打包文件,引入文件
java jar包解析:打包文件,引入文件 cmd下: jar命令:package包打包 javac命令:普通类文件打包 Hello.java: package org.lxh.demo; publi ...
- springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置
Log4j由三个重要的组件构成: 日志信息的优先级 日志信息的输出目的地 日志信息的输出格式 日志信息的优先级从高到低有ERROR.WARN. INFO.DEBUG,分别用来指定这条日志信息的重要程度 ...
- Java构造和解析Json数据的两种方法详解二
在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...
随机推荐
- Swift の 函数式编程
Swift 相比原先的 Objective-C 最重要的优点之一,就是对函数式编程提供了更好的支持. Swift 提供了更多的语法糖和一些新特性来增强函数式编程的能力,本文就在这方面进行一些讨论. S ...
- Mac系统Git生成ssh公钥
Mac系统Git生成ssh公钥 在使用Git仓库进行代码管理时,新的电脑上往往需要生成ssh公钥进行匹配,Mac系统生成Git公钥过程如下: 1.检查本机是否已有公钥 在终端中输入如下命令: ? 1 ...
- Git学习 -- 简介
Git是什么? 是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. 特点 分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者通过克隆(git clone),在本 ...
- android webview处理下载内容
url = "http://m.mumayi.com/"; WebView = (WebView) findViewById(R.id.webView1); WebView.get ...
- HDU 2609 How many
最小表示法+Map或者字典树,最小表示法找了个模板,还没学习呢... #include<cstdio> #include<cstring> #include<cmath& ...
- update set from where
原文链接:http://blog.csdn.net/xcbsdu/article/details/6736503 关于update set from where 下面是这样一个例子: 两个表a.b,想 ...
- PHP中将ip地址转成十进制数的两种实用方法
As we all know that long2ip works as ip1.ip2.ip3.ip4 (123.131.231.212) long ip => (ip1 * 256 * 25 ...
- hdu_5726_GCD(线段树维护区间+预处理)
题目链接:hdu_5726_GCD 题意: 给你n个数(n<=1e5)然后m个询问(m<=1e5),每个询问一个区间,问你这个区间的GCD是多少,并且输出从1到n有多少个区间的GCD和这个 ...
- ab测试 uwsgi遇到的问题
1 请求并发数目较大时,接收到的数目小于发送的数目 1.1 描述:uwsgi正常返回302跳转 ab -n 5000 -c 250 -g test.log "192.168.50.20:90 ...
- 剑指offer 判断树是不是对称的
html, body { font-size: 15px; } body { font-family: Helvetica, "Hiragino Sans GB", 微软雅黑, & ...