从内存分配角度看ArrayList与LinkedList

时间:2012-07-19 15:39:05

标签: java list collections arraylist linked-list

我需要存储大量信息,例如java list中的'names'。项目数量可以改变(或者简而言之,我不能预定义大小)。我认为,从内存分配的角度来看,LinkedList比ArrayList更好,对于ArrayList,一旦达到最大大小,内存分配自动加倍,因此总是有可能分配比内存更多的内存。需要什么。

我从其他帖子中了解到,存储在LinkedList中的单个元素占用的空间比ArrayList多,因为LinkedList也需要存储节点信息,但我仍然猜测我已定义的场景LinkedList可能是更好的选择。此外,我不想进入性能方面(获取,删除等),因为已经讨论过它。

5 个答案:

答案 0 :(得分:51)

LinkedList可能会分配更少的条目,但这些条目在天文数字上比ArrayList更昂贵 - 足以使最差情况ArrayList更便宜关注记忆。

(仅供参考,我认为你错了; ArrayList当它已满时增长1.5倍,而不是2倍。)

参见例如https://github.com/DimitrisAndreou/memory-measurer/blob/master/ElementCostInDataStructures.txtLinkedList每个元素消耗24个字节,而ArrayList每个元素最多消耗4个字节,最坏的情况是每个元素消耗6个字节。 (结果可能因32位与64位JVM和压缩对象指针选项而异,但在这些比较LinkedList中至少需要36个字节/元素,而ArrayList最多只需8个最糟糕的12。)

更新:

  

我从其他帖子中了解到,存储在LinkedList中的单个元素占用的空间比ArrayList多,因为LinkedList也需要存储节点信息,但我仍然猜测我已定义的场景LinkedList可能是更好的选择。此外,我不想进入性能方面(获取,删除等),因为已经讨论过它。

要明确的是,即使在最坏情况中,ArrayList比具有相同元素的LinkedList小4倍。使LinkedList获胜的唯一可行方法是通过调用ensureCapacity故意夸大价值来故意修正比较,或者在添加ArrayList之后删除大量值

简而言之,基本上不可能让LinkedList赢得内存比较,如果你关心空间,那么在trimToSize()上调用ArrayList会立即生成ArrayList再次大获全胜。认真。 ArrayList获胜。

答案 1 :(得分:5)

  

...但我仍在猜测我已定义的场景LinkedList可能是更好的选择

你的猜测不正确。

一旦超过了数组列表的初始容量,支持的大小将在1到2个引用之间乘以条目数。这是由于用于增长后备阵列的策略。

对于链表,每个节点至少占条目数的3倍,因为每个节点都有nextprev引用以及条目引用。 (事实上​​,它超过3次,因为节点的对象头和填充使用了空间。根据JVM和指针大小,它可以多达6次。)

链接列表使用的空间少于数组列表的唯一情况是,如果您严重高估了数组列表的初始容量。 (对于非常小的清单......)


当你考虑它时,唯一真正的优势链表就是数组列表就是在插入和删除元素时。即便如此,这取决于你是如何做到的。

答案 2 :(得分:2)

ArrayList.trimToSize()可能会让您满意。

  

将此ArrayList实例的容量调整为列表的当前容量   尺寸。应用程序可以使用此操作来最小化存储   一个ArrayList实例。

顺便说一句,在ArrayList Java6中,它不是双倍容量,它是最大大小的1.5倍。

答案 3 :(得分:2)

ArrayList每个对象使用一个引用(或者当它需要的大小加倍时使用两个引用)这通常是4个字节。

LinkedList仅使用其需要的节点,但每个节点可以是24个字节。

所以即使在最糟糕的情况下,ArrayList也会比LinkedList小3倍。

用于获取ARrayList支持随机访问O(1)但LinkedList是O(n)。为了从末尾删除,两者都是O(1),从中间的某个地方删除ArrayList是O(n)

除非您有数百万条目,否则收集的大小不太重要。首先重要的是条目的大小,无论使用何种集合,都是相同的。

答案 4 :(得分:2)

信封背面最坏情况:

数组中500,000个名称大小为1,000,000 = 500,000使用,500,000个空指针位于已分配数组的未使用部分。

链表中的500,000个条目=每个条目3个指针(节点对象保持当前,上一个和下一个)=内存中的1,5000,000个指针。 (然后你必须添加节点本身的大小)