Java:HashSet与HashMap

时间:2015-02-01 09:51:20

标签: java memory-management hash hashmap hashset

我有一个处理大量数据集的程序。这些对象最好存储在散列实现的容器中,因为程序一直在寻找容器中的对象。

第一个想法是使用HashMap,因为获取和删除此容器的方法更适合我需要的用途。

但是,我开始看到HashMap的使用非常耗费内存,这是一个主要问题,所以我认为切换到HashSet会更好,因为它只使用<E>,而不是<K,V>每个元素,但当我看到我学到的实现它使用底层的HashMap!这意味着它不会节省任何记忆!

所以这是我的问题:

  • 我所有的假设都是真的吗?
  • HashMap内存是否浪费?更具体地说,每个条目的开销是多少?
  • HashSet和HashMap一样浪费吗?
  • 是否还有其他基于哈希的容器会显着减少内存耗材?

    更新

根据评论中的要求,我将对我的程序进行一些扩展,hashMap意味着保存一对其他对象,以及一些数值 - 从它们计算的浮点数。一路上它抽出一些并进入新的对。给定一对,它需要确保它不会保持这对或删除它。可以使用浮点值或对象对象的hashCode来完成映射。

此外,当我说&#34;庞大的数据集&#34;我说的是~4 * 10 ^ 9个对象

3 个答案:

答案 0 :(得分:13)

有关this site关于java中集合性能的非常有用的提示。

  

HashSet建立在HashMap< T, Object >之上,其中值为a   单身“现在”的对象。这意味着the memory consumption of aHashSet is identical to HashMap:为了存储SIZE值,您需要 32 * SIZE + 4 * CAPACITY 字节(加上值的大小)。它绝对不是一个对记忆友好的系列。

     

THashSet可能是HashSet最简单的替换集合 - 它实现了Set和Iterable,这意味着您应该只在集合的初始化中更新单个字母。

     

THashSet使用单个对象数组作为其值,因此它使用 4 * CAPACITY 字节进行存储。如您所见,与JDK HashSet相比,在相同的加载因子的情况下,您将保存 32 * SIZE 字节,这是一个巨大的改进。

此外,我从here拍摄的图片可以帮助我们记住选择合适的收藏品

enter image description here

答案 1 :(得分:5)

  

我所有的假设都是真的吗?

使用HashSet实现HashMap是正确的,因此您不会使用HashSet来保存任何内存。

如果您要创建包含大量元素的地图,则应根据您的知识构建HashMap Entry,以防止反复重复(从而记忆颠簸)。

  

HashMap内存是否浪费?更具体地说,它的开销是多少   每个条目?

不,这不浪费。开销是基础数组(由initialCapacity修改的大小),以及每个键值对的0.75对象。除了存储键和值之外,入口对象还存储指向槽中下一个条目的指针(如果两个或多个条目占据底层阵列中的相同槽)。默认的loadFactor HashSet使基础数组大小保持在条目数的133%。

非常具体地说,每个条目的内存开销是:

  • 输入对象对密钥的引用
  • 条目对象对值
  • 的引用
  • 输入对象对下一个条目的引用,
  • 以及基础数组对条目的引用(除以加载因子)。

很难获得比基于散列的集合更多的修剪。

  

HashSet和HashMap一样浪费吗?

使用HashMap代替int,您将无法获得内存效率。

  

是否有任何其他基于哈希的容器将是显着的   更少的内存消耗品?

如果你的密钥是基元(例如Map s),那里有自定义的Set和{{1}}实现(在loadFactor中),它们使用更多内存有效的数据结构。

答案 2 :(得分:1)

HashSet确实使用与HashMap一样多的内存。 HasSet实现Set的两者之间的差异,即,它不关心与键相关联的任何值,仅关注特定值的存在与否。 HashMap关注的是每个键存储/检索(put / get)值。

虽然HashMap / HashSet将数据存储在一个通常比元素数量稍大的数组中,但这并不是一个问题,因为负载因子是0.75。这意味着当元素数量达到底层数组大小的75%时,HashMap将会增长。

比大地图更大的问题是许多空地图,因为HashMap的默认大小是16.这可以通过将初始容量设置为0来抵消。

然而,您也可以使用TreeMap,因为TreeMap基于引用而不是数组,您可能会浪费更多空间,尤其是对于较大的地图,除了也会失去一些速度。 TreeMap的主要好处是它将键保持在有序状态,所以如果你需要它们,那么这就是要走的路。

此外,当您不能或不想自定义实现密钥类型的equalshashCode方法时,可以将TreeMap用于编程原因。您可以为密钥类型制作比较器。例如,要基于不区分大小写的String创建映射/集,请使用String.CASE_INSENSITIVE_ORDER作为TreeSet的比较器