美文网首页
HashMap使用不当导致内存泄漏问题

HashMap使用不当导致内存泄漏问题

作者: 善思者_tin | 来源:发表于2020-01-17 08:56 被阅读0次

一、概述

首先我们再次熟悉hashmap存储过程。

当添加一个元素(key-value)时,首先计算key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素已经被放在数组同一位置了,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,就形成了链表,同一个链表上的Hash值是相同的,所以说数组存放的是链表。 JDK8中,当链表长度大于8时,链表就转换为红黑树,这样又大大提高了查找的效率。

HashMap使用不当导致内存泄漏问题

二、HashMap取数据过程

明白了存储数据过程,取数据就比较简单了,参见以下步骤:

(1) 获得key的hashcode,通过hash()散列算法得到hash值,进而定位到数组的位置。

// 根据key算出hash

        int hash = (key == null) ? 0 : hash(key);

        // 先算出hash在table中存储的index,然后遍历table下标为index的单链表

for (Entry<K,V> e = table[indexFor(hash, table.length)];

            e != null;

            e = e.next) {

            Object k;

            // 如果hash和key都相同,则把Entry返回

            if (e.hash == hash &&

                ((k = e.key) == key || (key != null && key.equals(k))))

                return e;

        }

        return null;

(2) 在链表上挨个比较key对象。 调用equals()方法,将key对象和链表上所有节点的key对象进行比较,直到碰到返回true的节点对象为止。

(3) 返回equals()为true的节点对象的value对象

三、 HashMap使用不当导致的内存泄露

从存储原理我们可以分析出,数据在数组中的存放位置,是取决于Key对象 hashCode() 方法的。一个对象的hashCode() 方法的值,一般来说都是和对象的内容相关的。那么,如果Key对象的成员取值变化了,它的hashCode() 基本上也会变化。

这样就会有问题了。

在存放进去的时候,和取出数值的时候,都是依赖Key 对象的hashCode计算的。

设想一下,一个KV对被put 到HashMap中的时候,hashCode 是A,然后这个时候修改了Key的内容,使得它的hashCode变化了;那么接下来再用 get 方法获取这个 Value 时,会用这个Key重新计算hashCode,然后去内部查找,由于hashCode已经变化了,所以这时是找不到的。

总结:Key存储对象,如果对象的值改变,hashcode也会跟着改变,再获取此对象,就获取为空。另外,HashMap内部还存在的它曾经对应的key,它会因为HashMap的持有而无法被GC回收,从而会导致内存泄漏。

四、解决方案

从以上的分析可以知道,该问题的本质原因,在一个Key被放进HashMap 和从 HashMap 取出时,两次计算它的 hashCode 不一致导致的。所以要避免这个问题,就需要保证一个 Key 在 put 和 get 时,它的hashCode 保持不变。

具体实现为:

1. 保证作为HashMap 的Key 的对象是不可变的。也就是使用只读多对象来当作Key;

2. 如果要使用一个类当作HashMap的key,同时也要修改它的内容。那么可以重写hashCode,保证hashCode 的生成只和某些不可变的成员相关。也就是说只要hashCode不变,通过hash()散列算法得到hash值,进而定位到数组的位置也不会变,如果后面再改变key的值,对存储位置不影响,只是不能获取到,不影响GC。如果Key改变,那么接下来再用 get 方法获取这个 Value 时,会用这个Key重新计算hashCode,然后去内部查找,由于hashCode已经变化了,所以这时是找不到的,存储那么这个在HashMap内部存在的它曾经对应的Node,将会导致内存泄漏。它会因为HashMap的持有而无法被GC回收,但是用HashMap却也获取不到它。

相关文章

网友评论

      本文标题:HashMap使用不当导致内存泄漏问题

      本文链接:https://www.haomeiwen.com/subject/reqczctx.html