Clear()是最安全的清空方式,只释放元素引用、重置计数器而不改变容量;反复new会增加GC压力;遍历时不可调用Clear();多线程需加锁或改用ConcurrentDictionary。

Clear() 是最安全的清空方式,别用 new 重建
直接调用 Clear() 方法即可清空所有键值对,内部只释放元素引用、重置计数器,不改变哈希表容量。反复用 new Dictionary<tkey tvalue>()</tkey> 替换旧字典,不仅多一次内存分配,还会让原字典对象滞留等待 GC——尤其在高频循环中容易触发 Gen0 频繁回收。
- 适用场景:需要保留字典实例(比如作为类字段被多处引用)
- 注意:如果字典里存的是大对象引用(如
byte[]、List<string></string>),Clear()后这些对象若无其他引用,会立刻可被回收 - 错误现象:用
dict = new Dictionary<int string>();</int>后发现其他地方还在读老字典,数据“没清掉”——其实是引用没更新
Clear() 不释放底层数组,容量不变
Clear() 只把 _count 设为 0,但底层数组(_buckets、_entries)仍保留原大小。这对后续快速重填有利,但如果清空后长期不再写入,或字典曾膨胀到很大(比如百万级),就浪费内存。
- 判断是否要重建:观察字典峰值大小与常态大小差距是否超过 5–10 倍
- 重建写法:
dict = new Dictionary<tkey tvalue>(dict.Capacity);</tkey>,显式传入合理容量避免立即扩容 - 兼容性注意:.NET 6+ 的
Dictionary支持构造时指定初始容量;.NET 5- 不支持传 0 容量,最小为 1
遍历中不能调用 Clear(),会抛 InvalidOperationException
和大多数 .NET 集合一样,Dictionary 在迭代过程中禁止结构修改。哪怕只是 Clear(),也会触发“集合已被修改”的异常,错误信息是:System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
- 正确做法:先收集要删的 key,再循环删除;或改用
ToList()克隆键集合后再清 - 示例避坑:
foreach (var key in dict.Keys.ToList()) dict.Remove(key);—— 比Clear()慢,但安全 - 性能提示:如果确定要全删且不在遍历中,就别硬套 foreach 场景,直接上
Clear()
线程不安全,多线程清空必须加锁或换 ConcurrentDictionary
Dictionary<tkey tvalue></tkey> 本身不是线程安全的。多个线程同时调用 Clear() 或一边清一边读/写,会导致状态不一致甚至崩溃(如 NullReferenceException 在内部哈希查找时抛出)。
- 简单加锁:用
lock (_dictLock) { dict.Clear(); },锁对象不能是dict自身(可能被设为 null) - 替代方案:改用
ConcurrentDictionary<tkey tvalue></tkey>,它提供Clear(),但注意——该方法在 .NET 6+ 才真正线程安全;.NET 5 及之前只是“尽力而为”,仍有竞态风险 - 容易忽略点:即使只读线程也受干扰——
Clear()过程中,其他线程调用ContainsKey()可能返回错误结果
清空动作看着简单,但涉及引用生命周期、内存布局、并发语义三层细节。尤其当字典作为缓存或状态容器长期存活时,Clear() 和重建的选择、锁的粒度、以及目标框架版本,都得看具体上下文才敢拍板。


















