开发经验随笔码农的世界程序员

HashMap内存泄露

2019-07-03  本文已影响40人  山东大葱哥

内存泄漏

在JAVA中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:

  1. 对象是可达的,即在有向图中,存在有向路可以与其相连;
  2. 对象是无用的,即程序以后不会再使用这些对象。

如果对象满足上面的1、2条件,这些对象就可以判定为JAVA中的内存泄漏,这些对象不会被GC所回收,然而他们却占用内存。

示例演示

/**
 * 测试HashMap的内存泄露
 */
public class HashMapLeakTest {
​
    public static void main(String[] args) {
        Map<HashKey, Integer> map = new HashMap<HashKey, Integer>();
        HashKey p = new HashKey("zhangsan","12333-suu-1232");
​
        map.put(p, 1);
        p.setName("lisi"); // 因为p.name参与了hash值的计算,修改了之后hash值发生了变化,所以下面删除不掉
        map.remove(p);
​
        System.out.println(map.size());
    }
}
​
/**
 * 用于测试的key 类
 */
class HashKey {
    private final String id;
    private String name;
​
    public HashKey(String name, String id) {
        this.name = name;
        this.id = id;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    @Override
    public int hashCode() {
        return name.hashCode()+id.hashCode();
    }
}

以上代码中运行会发现,在remove后,map的size仍然为1,也就是没有删除节点p,这个时候节点p在map中存在,也就是说该对象是可达的,然而该对象我们代码中时要删除的也就是说是没有用的对象了,所以这样就出现了内存泄露的情况。

原因分析

原因比较简单,就是因为这个对象hashCode在存放到HashMap之后发生了变化,我们去remove时按照新的hash值进行查找,而该对象是按照之前的旧的hash值存放在HashMap中,hash值发生了变化,导致查找的索引位置时不一样的,于是在HashMap中就无法这个对象,因此也就没有办法删除该节点。

解决方案

知道了原因,要解决这个问题或者避免这种内存泄露的情况发生,只需要对hashCode方法进行修改,不使用易变的字段参与hash计算,推荐使用final类型的字段计算hash值。

 @Override
    public int hashCode() {
        return id.hashCode();
    }

上述代码虽然解决了内存泄露的问题,但还存在内存溢出的情况。

上一篇下一篇

猜你喜欢

热点阅读