就内存而言,数组和java.util.Collection实现之间的区别

时间:2014-12-17 13:51:54

标签: java

当我们说数组内存分配时,它意味着在堆区域中分配的连续内存块。因此,假设数组中有100k个元素,JVM将查看堆区域,其中100k个连续内存块是空闲的。

根据理论,java Collection不是这种情况。收集下的所有元素都将通过哈希码分配到堆内存中,它可能是也可能不是连续的内存块。

现在我很困惑Collection如何以这种方式工作,因为Collection底层实现仅使用数组(例如ArrayList),这意味着数组的所有属性对Collection也是有效的。

需要帮助才能明确这一点。

3 个答案:

答案 0 :(得分:3)

如果Collection实现是ArrayList,那么与Object []相比几乎没有开销,其他实现可能占用更多的内存来保存相同数量的元素。例如。 LinkedList为每个元素都有一个节点:

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

元素的内存大约是Object []

的5倍

答案 1 :(得分:1)

由于ArrayList包装数组以提供可调整大小的存储,因此它需要的内存多于数组,而数组是一个连续的内存块,它已经知道当前的元素数。

答案 2 :(得分:1)

显然,事实内存消耗取决于正在运行的虚拟机作为对象的内存布局未由JVMS指定。使用OpenJDK附带的Java object layout等实用程序,您可以分析HotSpot上的实际实例大小。以下输出对于具有压缩OOPS的64位HotSpot v8_20b16实例有效。在此设置中,ArrayList实例消耗:

java.util.ArrayList object internals:
 OFFSET  SIZE     TYPE DESCRIPTION                    VALUE
      0    12          (object header)                N/A
     12     4      int AbstractList.modCount          N/A
     16     4      int ArrayList.size                 N/A
     20     4 Object[] ArrayList.elementData          N/A
Instance size: 24 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

Object[]消耗:

java.lang.Object[] object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4       (loss due to the next object alignment)
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

由此看来,ArrayList似乎比数组大得多。但是,我们应该查看实际实例,以便分析由集合的存储基础架构引起的开销并计算深度。让我们为Object[]数组和每1000个new Object()元素的列表执行此操作:

java.util.ArrayList instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1      4016      4016   [Ljava.lang.Object;
      1000        16     16000   java.lang.Object
         1        24        24   java.util.ArrayList
      1002               20040   (total)


[Ljava.lang.Object; instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1      4016      4016   [Ljava.lang.Object;
      1000        16     16000   java.lang.Object
      1001               20016   (total)

这几乎相同,因为ArrayList数组上Object[]的开销是不变的。与LinkedList相比,避免LinkedList$Entry s的大小非常小:

java.util.LinkedList instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
      1000        16     16000   java.lang.Object
         1        24        24   java.util.LinkedList
      1001        24     24024   java.util.LinkedList$Entry
      2002               40048   (total)

但是,不要过高估计单一分配的影响。留意您的记忆消耗,而是使用最符合您兴趣的集合类型。如果您发现问题,优化是适当的。