java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > WeakHashMap回收

Java中WeakHashMap的回收问题详解

作者:幸平xp

这篇文章主要介绍了Java中WeakHashMap的回收问题详解,WeakHashMap弱键大致上是通过WeakReference和ReferenceQueue实现,WeakHashMap的key是"弱键",即是WeakReference类型的,ReferenceQueue是一个队列,它会保存被GC回收的"弱键",需要的朋友可以参考下

一、四大引用

在介绍WeakHashMap回收问题之前,我们要先介绍四大引用类型:

对于本文主要涉及的为强引用,弱引用。其他引用本篇就不再多提了。 总结一下强引用与弱引用:

二、WeakHashMap的回收问题

首先基本大概讲述一下WeakHashMap弱键的原理:

大致上是通过WeakReference和ReferenceQueue实现的。WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。

实现步骤是:

1、新建WeakHashMap,将“键值对”添加到WeakHashMap中。实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。

2、当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。

3、 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。和HashMap一样,WeakHashMap是不同步的。可以使用 Collections.synchronizedMap 方法来构造同步的 WeakHashMap。

读者看到这可能还是比较抽象。没关系,接下来我们直接上一些例子:

public static void main(String[] args) {
        WeakHashMap<String,String> weakMap = new WeakHashMap<>();
        weakMap.put("k1","v1");
        String k2 = new String("k2");
        weakMap.put(k2,"v2");
        weakMap.put(new String("k3"),"k3");
        System.out.println("weakMap回收前打印结果:");
        System.out.println(weakMap);
        // 因为WeakHashMap内部维护的是一个弱引用映射所以gc直接回收
        System.gc();
        System.out.println("weakMap回收后打印结果:");
        System.out.println(weakMap);
    }

以上的打印结果是什么呢?

在这里插入图片描述

可以看到打印结果是回收后的结果是只有k3的key-value被回收掉了。那么为什么呢?

这得首先从创建一个String对象说起,创建一个String对象最常见的有两种情况:

// 第一种情况
String str1 = "a";
// 第二种情况
String str2 = new String("b");

对于第一种情况其对象的创建会先在字符串常量池判断有没有对应的字符串常量,如果没有创建一个字符串常量一,然后将其引用指向在字符串常量池中的那个常量,如果存在则不需创建直接返回引用。 对于第二种情况其对象的引用还是会先在字符串常量池判断有没有对应的字符串常量,如果没有创建一个字符串常量。 而后在堆中拷贝一个其字符串常量的对象,最后返回堆上的引用

我画了张图对于情况二来讲应该是这个:

在这里插入图片描述

那么对于对象创建的引用我们了解了,那么接下来回到例子就很好理解。

然后则是:

String k2 = new String("k2");
weakMap.put(k2,"v2");

这里面的很明显k2为new String的WeakHashMap外部的强引用因此k2的指针其实是在WeakHashMap外部被引用,所以不会被gc。如果要回收它也很容易,则只需要将其外部的引用k2置为null

String k2 = new String("k2");
weakMap.put(k2,"v2");
k2 = null;

而相对直接在WeakHashMap内直接创建对象返回引用的话,那么很明显就是弱键了。

weakMap.put(new String("k3"),"k3");

那么如何可以如何才能不回收这个字符串对象呢?我们刚刚画图提到了,我们可以用intern()方法返回其字符串常量池对应的对象

weakMap.put(new String("k3").intern(),"k3");

这个时候小伙伴可以自己去试一下,此时这个对象gc后也不会被回收了。就如同情况1:weakMap.put(“k1”,“v1”);

最后的最后附上完整代码,有兴趣的可以自己去试试:

public class MapGC {
    public static void main(String[] args) {
        WeakHashMap<String,String> weakMap = new WeakHashMap<>();
        weakMap.put("k1","v1");
        String k2 = new String("k2");
        weakMap.put(k2,"v2");
        weakMap.put(new String("k3"),"k3");
        System.out.println("weakMap回收前打印结果:");
        System.out.println(weakMap);
        // 因为WeakHashMap内部维护的是一个弱引用映射所以gc直接回收
        System.gc();
        System.out.println("weakMap第一次回收后打印结果:");
        System.out.println(weakMap);
        k2 = null;
        weakMap.put(new String("k3").intern(),"k3");
        System.gc();
        System.out.println("weakMap第二次回收后打印结果:");
        System.out.println(weakMap);
    }
}

输出结果:

在这里插入图片描述

到此这篇关于Java中WeakHashMap的回收问题详解的文章就介绍到这了,更多相关WeakHashMap回收内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文