public bool Purge(bool purgeAll) { bool foundDirt = false; if (!purgeAll) { // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = _dict.Keys; String[] keys = new String[ic.Count]; ic.CopyTo(keys, 0); for (int i = keys.Length - 1; i >= 0; --i) { if (keys[i] == AllListenersKey) { continue; // ignore the special entry for now } // for each key, remove dead entries in its list PropertyRecord pr = (PropertyRecord)_dict[keys[i]]; if (pr.Purge()) { foundDirt = true; } // if there are no more entries, remove the key if (pr.IsEmpty) { pr.StopListening(_type); _dict.Remove(keys[i]); } } if (foundDirt) { // if any entries were purged, invalidate the special entry _dict.Remove(AllListenersKey); _proposedAllListenersList = null; } if (IsEmpty) { StopListening(); } } else { // stop listening. List cleanup is handled by Purge() foundDirt = true; StopListening(); foreach (DictionaryEntry de in _dict) { PropertyRecord pr = (PropertyRecord)de.Value; pr.StopListening(_type); } } return(foundDirt); }
public bool Purge(bool purgeAll) { bool foundDirt = false; if (!purgeAll) { if (!MS.Internal.BaseAppContextSwitches.EnableWeakEventMemoryImprovements) { // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = _dict.Keys; String[] keys = new String[ic.Count]; ic.CopyTo(keys, 0); for (int i = keys.Length - 1; i >= 0; --i) { if (keys[i] == AllListenersKey) { continue; // ignore the special entry for now } // for each key, remove dead entries in its list PropertyRecord pr = (PropertyRecord)_dict[keys[i]]; if (pr.Purge()) { foundDirt = true; } // if there are no more entries, remove the key if (pr.IsEmpty) { pr.StopListening(_type); _dict.Remove(keys[i]); } } #if WeakEventTelemetry _manager.LogAllocationRelay(ic.GetType(), 1, 12); // dict.Keys - Hashtable+KeyCollection _manager.LogAllocationRelay(typeof(String[]), 1, 12 + ic.Count * 4); // keys #endif } else { Debug.Assert(_toRemove.Count == 0, "to-remove list should be empty"); // enumerate the dictionary using IDE explicitly rather than // foreach, to avoid allocating temporary DictionaryEntry objects IDictionaryEnumerator ide = _dict.GetEnumerator() as IDictionaryEnumerator; while (ide.MoveNext()) { String key = (String)ide.Key; if (key == AllListenersKey) { continue; // ignore the special entry for now } // for each key, remove dead entries in its list PropertyRecord pr = (PropertyRecord)ide.Value; if (pr.Purge()) { foundDirt = true; } // if there are no more entries, remove the key if (pr.IsEmpty) { pr.StopListening(_type); _toRemove.Add(key); } } // do the actual removal (outside the dictionary iteration) if (_toRemove.Count > 0) { foreach (String key in _toRemove) { _dict.Remove(key); } _toRemove.Clear(); _toRemove.TrimExcess(); } #if WeakEventTelemetry Type enumeratorType = ide.GetType(); if (enumeratorType.Name.IndexOf("NodeEnumerator") >= 0) { _manager.LogAllocationRelay(enumeratorType, 1, 24); // ListDictionary+NodeEnumerator } else { _manager.LogAllocationRelay(enumeratorType, 1, 36); // Hashtable+HashtableEnumerator } #endif } if (foundDirt) { // if any entries were purged, invalidate the special entry _dict.Remove(AllListenersKey); _proposedAllListenersList = null; } if (IsEmpty) { StopListening(); } } else { // stop listening. List cleanup is handled by Purge() foundDirt = true; StopListening(); foreach (DictionaryEntry de in _dict) { PropertyRecord pr = (PropertyRecord)de.Value; pr.StopListening(_type); } } return(foundDirt); }