The Labs \ Source Viewer \ SSCLI \ System.ComponentModel \ WeakHashtable

  1. //------------------------------------------------------------------------------
  2. // <copyright file="WeakHashtable.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.ComponentModel
  16. {
  17.    
  18.     using System;
  19.     using System.Collections;
  20.     using System.Security.Permissions;
  21.    
  22.     /// <devdoc>
  23.     /// This is a hashtable that stores object keys as weak references.
  24.     /// It monitors memory usage and will periodically scavenge the
  25.     /// hash table to clean out dead references.
  26.     /// </devdoc>
  27.     [HostProtection(SharedState = true)]
  28.     internal sealed class WeakHashtable : Hashtable
  29.     {
  30.         private static IEqualityComparer _comparer = new WeakKeyComparer();
  31.        
  32.         private long _lastGlobalMem;
  33.         private int _lastHashCount;
  34.        
  35.         internal WeakHashtable() : base(_comparer)
  36.         {
  37.         }
  38.        
  39.         /// <devdoc>
  40.         /// Override of clear that performs a scavenge.
  41.         /// </devdoc>
  42.         public override void Clear()
  43.         {
  44.             base.Clear();
  45.         }
  46.        
  47.         /// <devdoc>
  48.         /// Override of remove that performs a scavenge.
  49.         /// </devdoc>
  50.         public override void Remove(object key)
  51.         {
  52.             base.Remove(key);
  53.         }
  54.        
  55.         /// <devdoc>
  56.         /// Override of Item that wraps a weak reference around the
  57.         /// key and performs a scavenge.
  58.         /// </devdoc>
  59.         public void SetWeak(object key, object value)
  60.         {
  61.             ScavengeKeys();
  62.             this[new EqualityWeakReference(key)] = value;
  63.         }
  64.        
  65.         /// <devdoc>
  66.         /// This method checks to see if it is necessary to
  67.         /// scavenge keys, and if it is it performs a scan
  68.         /// of all keys to see which ones are no longer valid.
  69.         /// To determine if we need to scavenge keys we need to
  70.         /// try to track the current GC memory. Our rule of
  71.         /// thumb is that if GC memory is decreasing and our
  72.         /// key count is constant we need to scavenge. We
  73.         /// will need to see if this is too often for extreme
  74.         /// use cases like the CompactFramework (they add
  75.         /// custom type data for every object at design time).
  76.         /// </devdoc>
  77.         private void ScavengeKeys()
  78.         {
  79.             int hashCount = Count;
  80.            
  81.             if (hashCount == 0) {
  82.                 return;
  83.             }
  84.            
  85.             if (_lastHashCount == 0) {
  86.                 _lastHashCount = hashCount;
  87.                 return;
  88.             }
  89.            
  90.             long globalMem = GC.GetTotalMemory(false);
  91.            
  92.             if (_lastGlobalMem == 0) {
  93.                 _lastGlobalMem = globalMem;
  94.                 return;
  95.             }
  96.            
  97.             float memDelta = (float)(globalMem - _lastGlobalMem) / (float)_lastGlobalMem;
  98.             float hashDelta = (float)(hashCount - _lastHashCount) / (float)_lastHashCount;
  99.            
  100.             if (memDelta < 0 && hashDelta >= 0) {
  101.                 // Perform a scavenge through our keys, looking
  102.                 // for dead references.
  103.                 //
  104.                 ArrayList cleanupList = null;
  105.                 foreach (object o in Keys) {
  106.                     WeakReference wr = o as WeakReference;
  107.                     if (wr != null && !wr.IsAlive) {
  108.                         if (cleanupList == null) {
  109.                             cleanupList = new ArrayList();
  110.                         }
  111.                        
  112.                         cleanupList.Add(wr);
  113.                     }
  114.                 }
  115.                
  116.                 if (cleanupList != null) {
  117.                     foreach (object o in cleanupList) {
  118.                         Remove(o);
  119.                     }
  120.                 }
  121.             }
  122.            
  123.             _lastGlobalMem = globalMem;
  124.             _lastHashCount = hashCount;
  125.         }
  126.        
  127.         private class WeakKeyComparer : IEqualityComparer
  128.         {
  129.             bool IEqualityComparer.Equals(object x, object y)
  130.             {
  131.                 if (x.GetHashCode() == y.GetHashCode()) {
  132.                     WeakReference wX = x as WeakReference;
  133.                     WeakReference wY = y as WeakReference;
  134.                    
  135.                     if (wX != null) {
  136.                         if (!wX.IsAlive) {
  137.                             return false;
  138.                         }
  139.                         x = wX.Target;
  140.                     }
  141.                    
  142.                     if (wY != null) {
  143.                         if (!wY.IsAlive) {
  144.                             return false;
  145.                         }
  146.                         y = wY.Target;
  147.                     }
  148.                    
  149.                     return object.ReferenceEquals(x, y);
  150.                 }
  151.                
  152.                 return false;
  153.             }
  154.            
  155.             int IEqualityComparer.GetHashCode(object obj)
  156.             {
  157.                 return obj.GetHashCode();
  158.             }
  159.         }
  160.        
  161.         /// <devdoc>
  162.         /// A subclass of WeakReference that overrides GetHashCode and
  163.         /// Equals so that the weak reference returns the same equality
  164.         /// semantics as the object it wraps. This will always return
  165.         /// the object's hash code and will return True for a Equals
  166.         /// comparison of the object it is wrapping. If the object
  167.         /// it is wrapping has finalized, Equals always returns false.
  168.         /// </devdoc>
  169.         private sealed class EqualityWeakReference : WeakReference
  170.         {
  171.             private int _hashCode;
  172.             internal EqualityWeakReference(object o) : base(o)
  173.             {
  174.                 _hashCode = o.GetHashCode();
  175.             }
  176.            
  177.             public override bool Equals(object o)
  178.             {
  179.                 if (o == null) {
  180.                     return false;
  181.                 }
  182.                
  183.                 if (o.GetHashCode() != _hashCode) {
  184.                     return false;
  185.                 }
  186.                
  187.                 if (o == this || (IsAlive && object.ReferenceEquals(o, Target))) {
  188.                     return true;
  189.                 }
  190.                
  191.                 return false;
  192.             }
  193.            
  194.             public override int GetHashCode()
  195.             {
  196.                 return _hashCode;
  197.             }
  198.         }
  199.        
  200.        
  201.         /* The folowing code has been removed to prevent FXCOP violation
  202.           It is left here incase it needs to be resurected
  203.         /// <devdoc>
  204.         ///    Override of add that wraps a weak reference around the
  205.         ///    key and performs a scavenge.
  206.         /// </devdoc>
  207.         public void AddWeak(object key, object value)
  208.         {
  209.             ScavengeKeys();
  210.             base.Add(new EqualityWeakReference(key), value);
  211.         }
  212.         */       
  213.     }
  214. }

Developer Fusion