WeakHashMap 消除过期的对象引用 避免内存泄漏

WeakHashMap 消除过期的对象引用 避免OOM内存泄漏
  • 自己管理的内存(数组长度减小后,pop出的对象容易导致内存泄漏)
  • 缓存
  • 监听和回调
自己管理的内存
public class Stack{
  private Object[] elements;
 #   private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    public Stack(){
         elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e){
        ensureCapacity();
        elements[size++]=e;    // allocate新的堆内存和栈内存
    }

    public Object pop(){
        if(size==0) throw new EmptyStackException();
        return element[--size];    // pop出element[size],该对象不再有效。内存泄漏原因。
    }
    
    private void ensureCapacity(){
        if(elements.length==size)
            elements = Arrays.copyOf(elements, 2*size+1);
    }
}

弹出的对象不再有效,但JVM不知道,所以会一直保持该对象,没有gc进行回收,造成内存泄露。

解决:

主动设置为null,就没有原来对象的引用了,如果其他地方没有引用那就会被回收

  public Object pop(){
        if(size==0) throw new EmptyStackException();
        elements[size] = null;        // 等待回收
        return element[--size];
    }
缓存

缓存的对象容易被程序员遗忘,需要设置机制来维护缓存,

例如不定期回收不再使用的缓存(使用定时器)。某些情况下,使用WeakHashMap可以达到缓存回收的功效。注,只有缓存依赖于外部环境,而不是依赖于值时,WeakHashMap才有效。

监听或回调

使用监听和回调要记住取消注册。确保回收的最好的实现是使用弱引用(weak reference),例如,只将他们保存成WeakHashMap的键。

WeakHashMap

弱引用:一个对象具有弱引用,垃圾回收的时候,一定会被回收;

WeakHashMap:当除了自身有对key的引用外,此key没有其他引用,那么GC之后此map会自动丢弃此值;

WekHashMap 适用于缓存,保存的对象只要其他地方没有它的引用,就会被回收;

HashMap作为强引用,不主动将key删除,保存的对象内容是不会被垃圾回收的;

案例:

参考 weakHashMap 用法 - 疯狂的小萝卜头 - 博客园 (cnblogs.com)

@Test
public void weakTest() {
    String a = new String("a");
    String b = new String("b");
    Map weakmap = new WeakHashMap();
    Map map = new HashMap();
    map.put(a, "aaa");
    map.put(b, "bbb");

    weakmap.put(a, "aaa");
    weakmap.put(b, "bbb");

    //HashMap  remove 掉对象a
    map.remove(a);

    /**
     * 这里将a变量置为null,WeakHashMap中的a将自动被回收掉
     * 因为对于a对象,hashmap主动删除了对象a,除了WeakHashMap中有对象a的引用,其他地方没有指向a的引用;
     * 所以 WeakHashMap中的a将自动被回收掉
     */
    a = null;
    /**
     * 对于b对象,虽然没有b变量指向b对象的地址,但是HashMap里面还有b对象的引用
     * WeakHashMap中h还是会保留b对象的引用,而不会让gc回收
     */
    b = null;

    
    System.gc();
    Iterator i = map.entrySet().iterator();
    while (i.hasNext()) {
        Map.Entry en = (Map.Entry) i.next();
        System.out.println("map:" + en.getKey() + ":" + en.getValue());
    }
    Iterator j = weakmap.entrySet().iterator();
    while (j.hasNext()) {
        Map.Entry en = (Map.Entry) j.next();
        System.out.println("weakmap:" + en.getKey() + ":" + en.getValue());
    }
}


//结果
map:b:bbb
weakmap:b:bbb

声明了两个Map对象,一个是HashMap,一个是WeakHashMap,同时向两个map中放入a、b两个对象;

当HashMap remove掉a 并且将a、b都指向null时,WeakHashMap中的a将自动被回收掉。

出现这个状况的原因是,对于a对象而言,当HashMap remove掉并且将a指向null后,除了WeakHashMap中还保存a外已经没有指向a的指针了,所以WeakHashMap会自动舍弃掉a,

而对于b对象变量虽然指向了null,但HashMap中还有指向b的指针,所以WeakHashMap将会保留

总之,a对象最后只有WeakHashMap里面有引用被使用,其他地方没有,满足弱引用被回收的条件;

而b对象没有被HashMap主动remove,还是在HashMap里面有引用存在,所以不会被回收;

注意:不要使用基础类型作为WeakHashMap的key

案例:

@Test
public void weakHashMapTest() {
    WeakHashMap<Object, Object> map = new WeakHashMap<>();
    for (int i = 1; i <= 1000; i++) {
        map.put(i,new Object());
        System.gc();
        System.out.println("插入第"+i+"个的时候,map size:"+map.size());
    }
}

可以看到结果,最后大小只会停留在128左右;

因为使用int为key存入,会自动转为包装类Integer对象,维护了一个常量缓存,保存了-128到127的缓存,所以大于这个区间的对象,其他地方没有引用,只有WeakHashMap有引用,那就满足弱引用被垃圾回收的条件;

而属于这个区间的对象,在Integer的缓存里还有引用,就不会被垃圾回收;

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值