news 2026/4/24 5:27:44

266. Java 集合 - ArrayList vs LinkedList 内存使用深度剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
266. Java 集合 - ArrayList vs LinkedList 内存使用深度剖析

文章目录

  • 266. Java 集合 - ArrayList vs LinkedList 内存使用深度剖析
      • 🎯 开场提示:内存使用不是一个“固定值”
    • 📦 内存结构:为什么 `LinkedList` 更占内存?
      • 🔢 对比数据:1个元素 vs 1000个元素
      • 🔍 示例:不同初始化方式对内存的影响
      • 🧯 潜在陷阱:`ArrayList` 永远不会自动收缩!
      • 🔢 数学模型:在固定堆空间中能存多少元素?
        • `LinkedList`:
        • `ArrayList`:
      • 💡 实战建议与优化策略
      • 📌 结论

266. Java 集合 - ArrayList vs LinkedList 内存使用深度剖析

在性能优化中,我们常关注速度(Time),但别忽略了另一个关键因素:空间(Memory

今天我们就深入分析一下ArrayListLinkedList内存消耗方面的差异,并辅以示例与最佳实践建议,帮助你在开发中做出更聪明的集合选择。


🎯 开场提示:内存使用不是一个“固定值”

  • 不同的JVM、不同的内存配置会影响集合的内存布局。
  • 本文数据基于使用 OpenJDK 的 MemoryLayout 工具 测试的结果,在Java堆小于32GB时具有较高准确性。

📦 内存结构:为什么LinkedList更占内存?

我们先来看看LinkedList是如何存储数据的。

每一个元素,都会封装在一个Node节点对象中:

privatestaticclassNode<E>{Eitem;Node<E>next;Node<E>prev;}

每个节点包含:

  • 元素引用item
  • 指向前一个节点的prev
  • 指向后一个节点的next
  • 对象头(Object Header

⚠️ 总共约消耗24字节 / 元素(不包括存储的数据对象本身)。

ArrayList是一个简单的数组封装

Object[]elementData;

只存储元素本身引用,且连续分配,命中 CPU 缓存更容易。


🔢 对比数据:1个元素 vs 1000个元素

集合类型1个元素时内存占用trimToSize1000个元素时内存占用
ArrayList76 bytes44 bytes4,976 bytes
LinkedList56 bytesN/A24,032 bytes
List.of()26 bytesN/A不适合大容量场景

📌总结

  • 小容量时,如果你不手动trimToSize()ArrayList可能比LinkedList更浪费。
  • 大容量时,ArrayList明显更省内存,通常为LinkedList1/5

🔍 示例:不同初始化方式对内存的影响

// 方式 1:默认构造,会初始化数组大小为10varlist1=newArrayList<Integer>();list1.add(1);// 方式 2:间接调用 addAll,会触发默认构造varlist2=newArrayList<Integer>();list2.addAll(List.of(1));// 方式 3:通过另一个集合构造,数组大小为精确元素数varlist3=newArrayList<>(List.of(1));

✅ 推荐使用方式 3,避免无用空间。


🧯 潜在陷阱:ArrayList永远不会自动收缩!

ArrayList自动扩容,但不会自动收缩

ArrayList<String>list=newArrayList<>(1000);// ... add/remove 很多元素后System.out.println(list.size());// 比如现在只剩 10 个

即便元素只剩10个,内部数组仍可能保留了1000的空间。

✅ 使用trimToSize()主动释放空间!

list.trimToSize();// 回收多余空间

⚠️注意:下次再添加元素时,可能会再次触发扩容。


🔢 数学模型:在固定堆空间中能存多少元素?

设总堆大小为 H,我们看看在纯容器结构占用下:

LinkedList
  • 每个元素 ≈ 24 字节
  • 可容纳元素数 ≈H / 24
ArrayList
  • 最优情况:数组满用,≈ 4 字节/元素 ⇒H / 4
  • 平均情况:数组使用率 67% ⇒ ≈ 6 字节/元素 ⇒H / 6
  • 最坏情况:扩容中存在两个数组(旧+新)⇒ ≈ 10 字节/元素 ⇒H / 10

📊 对比图示(概念):

|EfficiencyComparison|Ratio(LinkedListvsArrayList)||------------------------|-------------------------------||最优情况|6倍节省||平均情况|4倍节省||最坏扩容中|2.4倍节省|

💡 实战建议与优化策略

场景建议集合原因
大量只存 1 个元素的列表List.of()最省内存,仅占26字节,且不可修改。
偶尔只有 1 个元素的可变列表ArrayList + trimToSize()兼顾性能与内存。可在添加完成后主动缩容。
大批量插入,后续 seldom 删除ArrayList更紧凑、更缓存友好,减少GC压力。
动态增删频繁,容量波动剧烈需手动调控手动调用trimToSize(),或重新构建。
栈/队列行为(头尾操作频繁)LinkedList插入删除成本恒定,但注意内存代价。

📌 结论

  • 内存敏感型应用场景中,ArrayList几乎总是更优的选择
  • 频繁创建小 List、特别是一元素 List,应避免默认构造ArrayList
  • 想节省内存又不需要修改?使用List.of()
  • ArrayListtrimToSize()是一个被低估的优化工具
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!