# Force ConcurrentDictionary in a Singleton Registry to Collect Removed Items/Space

I have the following class which is used in a WebApi AspNetCore application as a singleton instance to store Strategy objects (reference type). The class is

/// <summary>
/// </summary>
public class StrategyRegister : IStrategyRegister
{
private ConcurrentDictionary<long, Strategy> _registery;

public StrategyRegister()
{
_registery = new ConcurrentDictionary<long, Strategy>();
}

{
if (_registery.ContainsKey(strategy.Id))
throw new SystemException("The registry can never contain two identical strategy ids");
}

public bool TryRemove(long id)
{
if (!_registery.ContainsKey(id))
return true;

//GC.Collect();
return _registery.TryRemove(id, out _);
}

public Strategy TryGet(long id)
{
if (_registery.ContainsKey(id))
return _registery[id];
return null;
}

public IEnumerable<Strategy> GetRegisteredStrategies()
{
return _registery.Select(kvp => kvp.Value);
}
}


The problem is, as the ConcurrentDictionary grows large and items are removed, they are not being collected by the GC. I confirm this by adding the crude and nasty line GC.Collect() after every removal. When this is done, memory does not grow... I could make this "smarter" (still crude), by adding a timer to force collection every n seconds, but is there a better way, or should I be doing something obvious here?

• and you are sure that nothing else is using strategies when you remove them? – t3chb0t Jun 28 '19 at 15:54
• Yes, got it. It is indeed the ConcurrentDictionary. – MoonKnight Jun 28 '19 at 16:08
• I have checked the source myself. Some strange stuff occurring... "TryRemove does not really remove an element. All it does is changing linked list pointers to skip never assigning the value of an array element to null. This prevent GC from collecting old evicted objects." from here. Forced GC not really helping - just slowing the problem. – MoonKnight Jun 28 '19 at 16:41
• @dfhwze your suggestion seems to work. I tested it with a netcore2.2 console (1mln strings) and checked the results before and after with dotMemory and the old one is completely released and the memory usage drops by the expected amount (I removed every other element - or copied every other). – t3chb0t Jun 28 '19 at 17:37
• Interesting. Thanks very much for your time guys. – MoonKnight Jun 28 '19 at 17:55