请解释 C# 中的 ArrayPool 是什么,并说明通过何种方式使用它来降低集合分配带来的开销?
考察说明
考查对 ArrayPool 机制的理解及池化数组在减少 GC 压力方面的应用能力。
回答思路
- 【回答框架 1】ArrayPool<T> 是 .NET 提供的一个静态类,用于管理可复用的 T[] 数组池。它通过租借和归还数组来避免频繁分配和回收大数组,从而减少 GC 压力。
- 【回答框架 2】核心方法是 Rent(int minimumLength) 和 Return(T[] array)。Rent 返回一个长度至少为最小长度的数组,可能大于请求长度;Return 将数组归还池中,默认清空数组内容以便复用。注意必须归还租借的数组,且不能重复归还。
- 【回答框架 3】使用模式是:用 using 或 try-finally 确保归还。通常与 Memory<T> 或 Span<T> 配合,在临时缓冲区场景(如序列化、IO 处理)替代常规 new T[],能显著减少 LOH 分配。
- 【回答框架 4】配置上,可通过 ArrayPool<T>.Create 创建自定义池,设置最大数组长度和桶数量,以适应特定场景。默认池按 2 的幂分配桶,以平衡复用率和内存占用。
- 【回答框架 5】使用场景需权衡:小数组频繁租借可能有额外开销,适合较大或频繁分配的数组。此外,数组长度是至少语义,调用方需用实际返回长度,不能用请求长度。
- 【关键点 1】ArrayPool 通过复用数组减少 GC 分配,适用于临时大数组场景。
- 【关键点 2】必须成对调用 Rent 和 Return,并确保归还。
- 【关键点 3】返回的数组长度可能大于请求长度,使用实际长度。
- 【关键点 4】可自定义池参数以适配特殊场景。
- 【关键点 5】注意线程安全:池本身是线程安全的,但归还后的数组内容可能被复用。
- 【易错点 1】忘记归还导致池无法复用,增加内存占用。
- 【易错点 2】归还后继续使用数组,可能读到被覆盖的数据。
- 【易错点 3】租借后不检查实际长度,导致数组越界或数据截断。