【问题标题】:memory reallocation issue in Java ArrayList, HashSet and HashMapJava ArrayList、HashSet 和 HashMap 中的内存重新分配问题
【发布时间】:2017-03-24 02:39:36
【问题描述】:

看了一些非官方的参考资料,想在这里确认一下我的理解是正确的。假设我们不时添加新的(独特的)元素,

  1. ArrayList<T> 会重新分配内存,因为它的内存需要是连续的,当新插入的元素的内存增长超过某个阈值时,会发生更大的连续内存空间的重新分配,现有的元素会被移动到新分配的更大的连续内存空间;
  2. HashSet<T>HashMap<T> 没有这样的问题,因为它们的记忆不需要连续?

顺便说一句,如果有关于这些领域的好文章,也感谢您的参考。

问候, 林

【问题讨论】:

  • 阅读the javadoc。它说:当哈希表中的条目数超过负载因子和当前容量的乘积时,对哈希表进行重新哈希(即重建内部数据结构),使哈希表大约有两倍桶数
  • @LinMa 我评论中的引用摘自 HashMap 的 javadoc。我在评论中的链接链接到 HashMap 的文档。 HashSet 是使用 HashMap 实现的。你真的需要花一些时间仔细阅读。
  • LinkedList就是这样一种数据结构。 TreeSet 和 TreeMap 也是如此。但是你多虑了。不重新分配并不意味着它更快。 Map 和 List 的用途完全不同。如果需要列表,请使用列表。如果您需要一个集合,请使用一个集合。如果您需要地图,请使用地图。除了非常特定的用例之外,ArrayList 比 LinkedList 更快(并且使用更少的内存)。

标签: java arraylist hashmap hashset


【解决方案1】:

如果您查看 Java 8 (jre 1.8.0_71) 中 ArrayList<> 中的 add(E e) 方法的源代码,它会调用一个名为 ensureCapacityInternal(int minCapacity) 的方法。即每次将对象添加到 ArrayList 时都会调用此方法。这又调用了一系列方法,最后,如果 ArrayList 的大小较小以容纳新添加的元素,它会调用一个名为 grow(int minCapacity) 的方法。该方法如下图所示:

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

这将创建一个大小比初始数组大 1.5 倍的新数组,并将旧数组中的所有元素复制到新数组。这证明了你的观点。 1.

回到你的观点。 2,在HashMap&lt;K,V&gt;的情况下,它们是一种特殊类型的数组,包含键和值对。这个数组槽称为buckets。因此,您添加到 HashMap 中的每个对象都应正确覆盖 hashCode()equals() 方法。当您调用put(K key, V value) 方法时,它会通过计算您传递的键hash(Object key) 的#hash 来调用称为putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) 的方法。这个散列指示值对象应该去的桶位置。因此,这里的数组只表示对象进入的地址块。This线程更详细地解释了它。 我希望这就是你要找的。

【讨论】:

  • 感谢 sbaitmangalkar 提供这些细节,只是想澄清一下,HashMapHashSet,因为不需要在连续的内存空间中,所以不会发生元素重新分配,对吗?
  • 是的,不需要连续的内存位置,也不会发生重新分配。但每当地图动态调整大小时,现有条目都会重新分配。
  • 很高兴它对您有所帮助!
猜你喜欢
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多