Java集合-----WeakHashMap

Java四大引用

      在介绍WeakHashMap前,我们先来介绍一下Java中的四大引用。

      Java四大引用分别为:强引用、软引用、弱引用、虚引用。
      它们的作用分别是:灵活的控制对象的生命周期提高对象的回收几率。

强引用

      强引用:创建一个对象并把对象赋给一个引用变量。我们平时使用对象的方式就是强引用。
      强引用有引用变量指向时永远不会被回收,JVM宁愿抛出OutOfMemory错误也不会回收强引用对象。

软引用

      软引用:一般用于实现Java对象的缓存,可有可无。一般将有用但是非必须的对象用软引用进行关联。

      软引用一般用SoftReference类。只要是软引用关联的对象,在Java发生内存溢出异常之前,会将这些对象列入要回收的范围。如果回收后,发现内存还是不够,才会抛出OutOfMemory异常。

      作用:软引用可以用来实现内存敏感的告诉缓存,比如网页缓存、图片缓存等,使用软引用能防止内存泄漏。

      举个例子:
            首先我们设置JVM初始内存为3M,最大可用内存为5M。我们来看一看在限制了JVM内存的情况下,下面代码能否正常运行:

public class SofetReferenceTest {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024*1024*3];
   }
}

            我们创建了一个大小为3M的数组,可以正常运行。

            此时,我们修改数组的大小为5M。看看能否正常运行。

byte[] buffer = new byte[1024*1024*5];

在这里插入图片描述
            我们可以看到,抛出了OutOfMemory异常。这是由于,我们是以强引用的形式创建的数组,即使JVM内存不够,强引用也不会被JVM回收。所以会抛出OutOfMemory。

            接下来我们看看软引用有什么不同。我们创建了10个大小为1M的数组,并用SoftReference关联。然后调用垃圾只回收机制

public static void main(String[] args) {
        ArrayList<Object> arrayList = new ArrayList<>();
        byte[] buffer = null;
        for (int i = 0; i < 10; i++) {
            buffer= new byte[1024*1024];
            SoftReference<byte[]> softReference = new SoftReference<>(buffer);
            arrayList.add(softReference);
    }
        System.gc();
        for (int i = 0; i < 10; i++) {
            Object o = ((SoftReference) arrayList.get(i)).get();
            System.out.println(o);
        }

    }

            我们可以看到,软引用关联的对象在内存不够的情况下,会被JVM回收。
在这里插入图片描述
            如果一个对象剩下的唯一一个引用为软引用时,则这个对象是软可及的。

      作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性外,也具有Java对象的一般性。所以当软可及对象被回收后。虽然这个SoftReference对象的get()返回null,这个SoftReference对象已经不再具有价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。所以提供了ReferenceQueue类。如果在创建SofetReference对象的时候,使用一个ReferenceQueue对象作为参数提供给SoftReference的构造方法时:

ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);

当这个SoftReference所创建的软引用被垃圾回收机制回收的同时,JVM会将这个软引用加入到与之关联的引用队列中。在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。一个软引用对象被回收的同时,会被放入ReferenceQueue队列中。所以我们可以判断ReferenceQueue是否为空,来检查哪个SoftReference对象已经被回收了。

弱引用

      弱引用,用来描述非必须对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。使用WeakReferece类来管理弱引用对象。

public static void main(String[] args) {
        // 一个强引用对象
        Person p1 = new Person(1,"王五");
        WeakReference w = new WeakReference(p1);
    
        System.out.println(w.get());//Person{id=1, name='王五'}
        p1 = null; // 取消强引用指向
        System.gc();
        System.out.println(w.get());//null
    }

      只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象指仅仅被弱引用关联,如果还存在其他强引用同时与之关联,则垃圾回收时不会回收该对象(软引用也是如此)

虚引用

      使用PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。虚引用一般用来检测对象是否被回收。

      虚引用必须和引用队列关联使用。垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

WeakHashMap

概述

      WeakHashMap中的键相比于HashMap不同。WeakHashMap中的键是"弱键",在WeakHashMap中,当某个键不再正常使用时,会被WeakHashMap中自动移除。

      "弱键"是通过WeakReference和ReferenceQueue实现的。

      当某"弱键"不再被其他对象引用,并被gc回收时,在gc回收该键的同时,这个弱键会被添加到ReferenceQueue(queue)中。当下一次,我们需要操作WeakHashMap时,会首先同步table和queue。table中保存了全部的键值对,queue中保存了已经被gc回收的键值对,同步它们就是删除table中被gc回收的键值对。

expungeStaleEntries()

      expungeStaleEntries()内部实现了移除其内部不用的entry从而达到自动释放内存的目的。我们每访问依次WeakHashMap的时候,都会调用该函数将table中已经被回收的键值对清理一遍。

    private void expungeStaleEntries() {
    // 遍历每一个被回收的entyry。
        for (Object x; (x = queue.poll()) != null; ) {
        // 加锁删除
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                    // 计算在table中位置。
                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;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值