Background and motivation
Weak references are widely used for tracking objects meanwhile allowing them to be collected by GC. In current API, WeakReference<T> provides decent support for tracking individual objects. There is also need for weakly tracking a collection of objects effectively. Sample usages include:
- Weak event pattern, register events and automatically deregister when the handler object is collected.
- Data binding, an object listening changes to data source, or multiple-way binding of more objects, allowing each bound objects to be collected separately.
The current workarounds for managing collections of weak references including:
- Use
ConditionalWeakTable. The implementation of ArrayPool<T>.Shared uses the key of ConditionalWeakTable<TKey, TValue> to weakly track references. The value slots are not used and always set to null. This can lead to more overhead for the value field storing.
- Manipulating
WeakReference together with ConditionalWeakTable. Example: WeakEventManager of WPF.
- Manually manipulate lists of
WeakReference. When invoked, manually check each weak reference and remove collected ones.
To simplify weak reference management and reduce potential overhead, collections of weak references are desired. BCL built-in support also provides more confidence of correctness and efficiency.
API Proposal
namespace System
{
public class WeakCollection<T> : IEnumerable<T>
where T : notnull // or class instead?
{
public void Add(T item);
public void Trim();
public bool Contains(T item);
public bool Remove(T item);
public Enumerator GetEnumerator();
public struct Enumerator : IEnumerator<T>
{
public bool MoveNext();
public T Current { get; }
}
}
}
API Usage
class BindableObject
{
private readonly WeakList<BindableObject> bounded;
void InvokeValueChanged(string newValue)
{
foreach (BindableObject o in bounded)
{
if (bounded != this)
bounded.NotifyValueChanged(newValue);
}
}
}
Alternative Designs
-
Implement ICollection<T>, IList<T>, or providing indexer ?
Count and indexing are not clearly defined when some objects are collected by GC.
-
Make the collection aware of GC, or make GC aware of the collection?
Ideally, the self-cleanup should run when GC happens. For maximum memory efficiency, GC may specially recognize this collection and mark the object references inside it as "weak". When GC moves the storage of the collection, it can also compact it. This would require on-heap weak reference support, which can be very challenging.
Making the collection aware of GC should be considerably simpler. It can use WeakReference or GCHandle to track the objects, and skips collected objects during enumeration. Implicit trimming can be triggered for add, remove, or GC collecting events.
Risks
The complexity and correctness when providing more integrated support from GC.
Background and motivation
Weak references are widely used for tracking objects meanwhile allowing them to be collected by GC. In current API,
WeakReference<T>provides decent support for tracking individual objects. There is also need for weakly tracking a collection of objects effectively. Sample usages include:The current workarounds for managing collections of weak references including:
ConditionalWeakTable. The implementation ofArrayPool<T>.Shareduses the key ofConditionalWeakTable<TKey, TValue>to weakly track references. The value slots are not used and always set tonull. This can lead to more overhead for the value field storing.WeakReferencetogether withConditionalWeakTable. Example:WeakEventManagerof WPF.WeakReference. When invoked, manually check each weak reference and remove collected ones.To simplify weak reference management and reduce potential overhead, collections of weak references are desired. BCL built-in support also provides more confidence of correctness and efficiency.
API Proposal
API Usage
Alternative Designs
Implement
ICollection<T>,IList<T>, or providing indexer ?Count and indexing are not clearly defined when some objects are collected by GC.
Make the collection aware of GC, or make GC aware of the collection?
Ideally, the self-cleanup should run when GC happens. For maximum memory efficiency, GC may specially recognize this collection and mark the object references inside it as "weak". When GC moves the storage of the collection, it can also compact it. This would require on-heap weak reference support, which can be very challenging.
Making the collection aware of GC should be considerably simpler. It can use
WeakReferenceorGCHandleto track the objects, and skips collected objects during enumeration. Implicit trimming can be triggered for add, remove, or GC collecting events.Risks
The complexity and correctness when providing more integrated support from GC.