ArrayPool
为什么用 ArrayPool 而不是 new T[n]?
每次
new byte[4096]都会触发堆分配;高频调用时容易产生大量 Gen 0 对象,增加 GC 频率。而 ArrayPool
怎么正确租借和归还数组?
租借后必须配对归还,否则池中可用数组减少,可能退化为每次都 new。推荐用
try/finally或
using(C# 8+ 支持
IDisposable的池实例): ✅ 推荐写法(自动归还):
using var buffer = ArrayPool<byte>.Shared.Rent(8192);<br> // 使用 buffer.Array,注意长度是 buffer.Length,不是 buffer.Array.Length✅ 手动归还(需确保执行):
var buffer = ArrayPool<byte>.Shared.Rent(8192);<br>
try { /* 使用 */ }<br>
finally { ArrayPool<byte>.Shared.Return(buffer); }
❌ 错误:只 Rent 不 Return → 池耗尽后后续 Rent 可能 new 新数组,失去池意义
如何控制池行为?自定义 ArrayPool
Shared 是开箱即用的默认池,适合通用场景。如需定制(比如限制最大数组大小、控制池容量或启用清零),可继承 ArrayPool
ArrayPool<byte>.Create(maxArrayLength: 65536, maxArraysPerBucket: 50)</byte>—— 控制单桶最大长度和数量 传入
clearArray: true可让 Return 时自动清零(防止数据残留,但有性能开销) 自定义实现需重写
Rent/
Return,一般没必要,除非有特殊复用逻辑(如按用途分池)
常见误区和注意事项
数组池不是万能银弹,用错反而影响性能:
租借的数组长度 ≥ 请求长度,但实际可用长度是buffer.Length,不是你传的 size —— 别越界写 不要跨线程长期持有(尤其异步未完成就 Return),但池本身线程安全,Rent/Return 可在不同线程调用 小数组(如 字节)可能被 JIT 内联优化,池收益不大;大数组(> 85KB)进 LOH,池价值更明显 Return 时若数组被修改过且不清零,下次 Rent 可能拿到脏数据 —— 关键业务建议显式清零或设 clearArray: true
基本上就这些。用好 ArrayPool
