我在互联网上搜索了很多,以找到一个C#实现,它可以允许使用弱引用来缓存不可变对象,以减少内存占用(类似于.NET String.Intern)。
就我而言,我需要缓存多个产品列表,每个列表中都可以显示相同的产品:
我找到了一个旧帖子,要求提供此类功能,但没有人能够提出实施Any weak interning collections (for immutable objects)
我已经实现了一个实现,但我需要确保它已准备就绪并且此代码中没有隐藏竞争条件或其他线程问题。
// Inspired by: http://www.nesterovsky-bros.com/weblog/2014/01/08/WeakTable.aspx
public static class ObjectCache<T> where T : class
{
#region Inner classes
public enum ElementState : byte
{
Uninitialized = 0,
Initialized = 1,
Finalized = 2
}
private class Element
{
public readonly T Value;
public ElementState State;
public Element(T value)
{
State = ElementState.Uninitialized;
Value = value;
}
~Element()
{
if (State == ElementState.Initialized)
{
State = ElementState.Finalized;
WeakReference<Element> state;
Values.TryRemove(this, out state);
}
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
private class WeakEqualityComparer : IEqualityComparer<object>
{
private readonly IEqualityComparer<T> _innerComparer;
public WeakEqualityComparer(IEqualityComparer<T> innerComparer)
{
_innerComparer = innerComparer;
}
public new bool Equals(object x, object y)
{
if (x == y) return true;
var xRef = x as WeakReference<Element>;
var xElem = xRef == null ? x as Element : GetTarget(xRef);
var yRef = y as WeakReference<Element>;
var yElem = yRef == null ? y as Element : GetTarget(yRef);
if (xElem == yElem) return true;
if (xElem == null || yElem == null) return false;
// If xState is finalized, then we are within the Finalizer and we want to
// search by reference to specifically remove this item.
if (xElem.State == ElementState.Finalized) return false;
// If we are looking for an element but this one is currently being finalized,
// we dont want to return it because it is going to disappear from the cache soon.
if (xElem.State == ElementState.Uninitialized && yElem.State == ElementState.Finalized) return false;
return _innerComparer.Equals(xElem.Value, yElem.Value);
}
public int GetHashCode(object obj)
{
return obj is WeakReference<Element>
? (GetTarget((WeakReference<Element>) obj)?.GetHashCode() ?? obj.GetHashCode())
: obj.GetHashCode();
}
}
#endregion Inner classes
private static readonly ConcurrentDictionary<object, WeakReference<Element>> Values = new ConcurrentDictionary<object, WeakReference<Element>>(new WeakEqualityComparer(EqualityComparer<T>.Default));
public static int Count => Values.Count;
public static T Intern(T item)
{
if (item == null)
return null;
Element initialElement = new Element(item);
WeakReference<Element> weakInitialState = new WeakReference<Element>(initialElement, true);
Element newElement;
do
{
newElement = GetTarget(Values.GetOrAdd(weakInitialState, x =>
{
initialElement.State = ElementState.Initialized;
return weakInitialState;
}));
} while (newElement == null);
return newElement.Value;
}
public static TRef GetTarget<TRef>(WeakReference<TRef> value) where TRef : class
{
TRef target;
value.TryGetTarget(out target);
return target;
}
}
在这段代码中,有一个WeakReference,其中trackRessurection对每个项都有活动,当其中一个被垃圾收集时,最终的被捕获并用于从ConcurrentDictionary中清除它自己。我发现了以下可能存在问题的案例:
还有其他奇怪的情况吗?