C#:数组与列表的差异

C# 数组(Array)是‌固定长度‌的连续内存块,适合‌已知规模、高频只读 ‌场景;泛型列表(List<T>)是‌动态扩容 ‌的封装结构,适合‌规模不确定、需频繁增删‌场景。两者索引访问均为 O(1),但底层开销与内存行为差异显著。

关键差异对比

表格

维度 数组 (T[]) 列表 (List<T>)
长度可变性 ❌ 创建后不可变(需 Array.Resize 重建) ✅ 自动扩容(默认策略:容量不足时翻倍)
内存布局 纯连续内存,无额外字段,GC 压力小 内部含数组 + Count/Capacity 字段;未设容量时易产生冗余空间
访问性能 极快(IL 指令 ldelem 直接寻址,缓存友好) 略慢(含方法调用、边界检查;Debug 模式更明显)
增删操作 不支持原生增删;中间插入/删除需手动移动元素(O(n)) Add() 均摊 O(1)(尾部);Insert/RemoveAt 为 O(n)(需移位)
功能丰富度 基础操作(索引、LengthArray.Sort 等) 丰富方法(Add/Remove/Find/Contains/LINQ 兼容等)
类型安全 泛型原生支持,值类型零装箱 泛型实现,值类型零装箱(优于非泛型 ArrayList
典型场景 图像像素缓冲、配置常量表、高频遍历固定数据集 用户输入收集、运行时对象列表、迭代开发中数据量不确定场景

性能与优化要点

  • 内存占用 ‌:未预设容量的 List<T> 因多次扩容,峰值内存可达同规模数组的‌5~10 倍 ‌;建议用 new List<T>(expectedSize) 预分配。
  • GC 影响 ‌:短生命周期大 List 易触发 Gen0 GC;局部小数组常被 JIT 优化至栈上(配合 Span<T> 可进一步零分配)。
  • 多维支持 ‌:数组原生支持多维(int[,]);List<T> 仅一维,嵌套列表效率低且内存不连续。
  • 接口抽象 ‌:对外暴露集合时优先用 IReadOnlyList<T>Span<T>(.NET Core 2.1+),避免泄露具体实现。

选择决策流

  1. 数据量是否‌创建时已知且永不变更 ‌? → ‌‌:用数组
  2. 是否需‌频繁在中间插入/删除 ‌? → ‌ ‌:评估 LinkedList<T> 或保留 List<T>(小数据量可接受 O(n))
  3. 是否需‌动态增长 + 丰富操作 + LINQ ‌? → ‌ ‌:用 List<T>(务必预设容量)
  4. 极端性能敏感(如游戏帧循环、高频交易)且数据固定? → ‌优先数组 ‌,必要时结合 Span<T> 避免拷贝。

注:Array.Resize 本质是新建数组 + 复制,非真正"扩容";避免在高频路径中反复创建集合实例。

相关推荐
wuyk5552 分钟前
Python实战项目02:学生成绩管理系统(控制台|CSV导出|完整落地)
开发语言·python
浪子明X7 小时前
十六位账本怎样发现传输差错:Internet Checksum 生活类比
开发语言
xiangyun6110 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun6110 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
唐青枫11 小时前
对象到底住在哪里?C#.NET 托管堆从分配、GC 到内存排查
c#·.net
白远山11 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
DevRay12 小时前
Java 21虚拟线程深度实战:告别线程池焦虑,百万并发吞吐量直接翻倍(原理+代码+避坑)
java·开发语言
free-elcmacom12 小时前
C++学习<1>程序分区
开发语言·c++
醉颜凉12 小时前
Java 必看:如何彻底避免 HashMap 多线程死循环问题?
java·开发语言
默 语12 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重