objectpool 仅在创建成本高、可安全重置、高频短生命周期场景下有效;盲目池化 stringbuilder 或不可变对象反而降低性能,且需正确配置 ipooledobjectpolicy 并确保 return() 在 finally 中执行。

ObjectPool
Get() 返回 null?检查 IPooledObjectPolicy 是否传了
直接 new DefaultObjectPool<stringbuilder>()</stringbuilder> 会返回 default(StringBuilder)(即 null),不是 bug,是设计强制你声明策略。常见错误包括:
- 用了无参构造函数,没传
IPooledObjectPolicy<t></t> - 传了
null策略(比如new DefaultObjectPool<stringbuilder>(null)</stringbuilder>) - 误以为
DefaultPooledObjectPolicy<t></t>对所有类型都自动清空——它只对StringBuilder、MemoryStream等少数 BCL 类型硬编码了Clear()或重置逻辑
正确写法:var pool = new DefaultObjectPool<stringbuilder>(new DefaultPooledObjectPolicy<stringbuilder>());</stringbuilder></stringbuilder> 或更推荐用 provider:var pool = new DefaultObjectPoolProvider().Create(new DefaultPooledObjectPolicy<stringbuilder>());</stringbuilder>
Return() 没生效?90% 是执行路径被截断
现象是“每次 Get() 都拿到新实例”,实际不是池坏了,而是 Return() 根本没跑完。典型断点:
-
async void方法里调Return(),方法提前退出,归还不执行 - try 块里抛异常,
Return()在 finally 外,直接跳过 -
Return()前字段被设为null,导致策略的Return(T obj)方法内判空失败并抛异常,池捕获后直接丢弃该实例 - 对象已超出
MaximumRetained上限(默认 100),被 GC 掉而非入池
安全模式必须包在 finally 里:var item = pool.Get(); try { /* use */ } finally { pool.Return(item); }
自定义类池化?IPooledObjectPolicy.Create/Return 必须配对清理
对自定义类(如含 byte[]、Dictionary、状态标记的 DTO),DefaultPooledObjectPolicy<t></t> 完全无效。必须实现 IPooledObjectPolicy<t></t> 并手动控制:
-
Create():只在这里分配昂贵资源(如大数组、连接上下文) -
Return(T obj):必须重置所有可变字段(Array.Clear()、list.Clear()、isProcessed = false),且返回true表示允许回收;返回false则对象被丢弃 - 禁止在
Return()里做阻塞操作(日志、锁、IO),否则拖慢所有归还路径
示例关键片段:public bool Return(MyBuffer obj) { obj.Position = 0; Array.Clear(obj.Data, 0, obj.Data.Length); return true; }
池越大多越好?MaximumRetained 调高前先看代价
DefaultObjectPoolProvider 默认 MaximumRetained = 100,超出对象直接 GC。调大看似“更复用”,实则引入三重风险:
- 内存常驻更多对象,GC 压力前移(尤其含大缓冲区时)
- CPU 缓存行失效上升,局部性被破坏
- 多线程争抢同一个
ConcurrentStack<t></t>,极端 QPS 下出现 cache line bouncing 抖动
真正有效的优化不是堆大小,而是分池:AsyncLocal<objectpool>></objectpool> 每线程一池,或按租户 ID 哈希分桶,避免竞争。同时确认你的对象真值得池化——JsonSerializerOptions 这类不可变对象,new 成本极低,池化反增开销。











