No, the ConcurrentDictionary<K,V>.TryRemove
method doesn't release all allocated memory. It releases the memory associated with the removed key (a Node
), but it doesn't shrink the array where the nodes are stored. The amount of memory wasted by a partially filled ConcurrentDictionary<K,V>
is significantly less than the amount of memory wasted by a partially filled Dictionary<K,V>
, and that's why currently (.NET 9) the ConcurrentDictionary<K,V>
is not equipped with an API similar to the Dictionary<K,V>.TrimExcess
.
Adding the TrimExcess
to the ConcurrentDictionary<K,V>
has been proposed in this GitHub proposal, but it didn't go anywhere and it was eventually closed. Quoting from this proposal:
ConcurrentDictionary
stores its data differently than does aDictionary
; the vast majority of memory it consumes is stored in nodes per element, rather than one large array.
ConcurrentDictionary._tables._buckets
is aNode
array, whose length can be even greater than the number of elements, and this array will not shrink when the elements are removed.Yes, but all it stores are the node references; with
Dictionary
, each entry stores both theTKey
and theTValue
and additional state (a hash code and next link).The references also occupy a lot of memory. On 64-bit systems, for simple key/value, e.g.
ConcurrentDictionary<int, int>
, a reference takes about 40% memory of a Node.A reference is 8 bytes on 64-bit. Can you please share code for the scenario that's causing you to want such a method?