e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
228 lines
7.0 KiB
C#
228 lines
7.0 KiB
C#
//------------------------------------------------------------------------------
|
|
// <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);
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|