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