You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何List<T>采用自有缓存空数组而非Array.Empty<T>?

关于List自定义空数组缓存的技术疑问解答

先看对应的List代码片段:

#pragma warning disable CA1825, IDE0300 // avoid the extra generic instantiation for Array.Empty<T>()
private static readonly T[] s_emptyArray = new T[0];
#pragma warning restore CA1825, IDE0300

该缓存空数组会在List<T>.ToArray()(列表为空时)等场景中被使用。

下面针对疑问逐一解答:

1. 为何要自定义缓存空数组?为何Array.Empty被视为需要避免的“额外泛型实例化”?

Array.Empty<T>()的实现依赖独立的泛型静态类EmptyArray<T>,内部持有空数组实例。调用Array.Empty<T>()时,CLR需要先实例化EmptyArray<T>这个泛型类;而List<T>本身已是泛型类,自身持有s_emptyArray可以避免额外的泛型类实例化开销——无需再加载、初始化EmptyArray<T>这个额外泛型类型。

2. 若其他地方使用了Array.Empty,运行时会存在两个缓存空实例,此时s_emptyArray反而成了额外实例化?

这种情况确实存在,但对于List<T>这类高频使用的核心集合,自有缓存的收益远大于“多一个实例”的成本:

  • List<T>的使用量极大,绝大多数场景下,List<T>的空数组访问频次远高于直接调用Array.Empty<T>()的情况,自有缓存能减少大量EmptyArray<T>的实例化触发。
  • 空数组本身内存开销极小(仅数组元数据,无元素存储),多一个实例的内存成本几乎可以忽略。

3. 是为了规避Array.Empty委托给EmptyArray的性能影响?这种泛型访问的性能影响是否足以证明合理性?

是的,核心目的就是减少泛型类型加载与访问的开销。Array.Empty<T>()需要跨泛型类访问静态字段,而List<T>的s_emptyArray是自身类的静态字段,访问路径更短:

  • 直接访问自身类静态字段,无需额外的类型解析、加载步骤,在高频调用场景(比如大量空List转数组)中,性能差异会被放大。
  • 官方团队通过性能测试验证过该优化的收益,对于List<T>这类基础核心库组件,哪怕是微秒级的性能提升,在大规模应用中都会累积成显著的优化效果。

4. 在高性能场景下,我们是否也应考虑创建并使用自有缓存空数组?

分场景判断:

  • 如果你的代码是高频调用的泛型类/方法,且空数组是常用路径,那么自定义缓存空数组是值得的,能避免额外的泛型类型实例化和跨类访问开销。
  • 如果是普通业务代码,或空数组使用频率很低,完全没必要——Array.Empty<T>()已经足够高效,额外维护自有缓存会增加代码复杂度,收益远小于成本。

内容的提问来源于stack exchange,提问作者user764754

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:32:38