前言 上一篇文章主要介紹了ObjectPool的理論知識,再來介紹一下Microsoft.Extensions.ObjectPool是如何實現的. 核心組件 ObjectPool ObjectPool 是一個泛型抽象介面,他抽象了兩個方法Get和Return Get方法用於從對象池獲取到可用對象,如 ...
前言
上一篇文章主要介紹了ObjectPool的理論知識,再來介紹一下Microsoft.Extensions.ObjectPool是如何實現的.
核心組件
ObjectPool
ObjectPool是一個泛型抽象介面,他抽象了兩個方法Get和Return
- Get方法用於從對象池獲取到可用對象,如果對象不可用則創建對象並返回出來
- Return方法用戶將對象返回到對象池
/// <summary>
/// A pool of objects.
/// </summary>
/// <typeparam name="T">The type of objects to pool.</typeparam>
public abstract class ObjectPool<T> where T : class
{
/// <summary>
/// Gets an object from the pool if one is available, otherwise creates one.
/// </summary>
/// <returns>A <typeparamref name="T"/>.</returns>
public abstract T Get();
/// <summary>
/// Return an object to the pool.
/// </summary>
/// <param name="obj">The object to add to the pool.</param>
public abstract void Return(T obj);
}
ObjectPoolProvider
ObjectPoolProvider是一個抽象介面他內置了Create的泛型方法和Create的泛型抽象方法,他是一個基於預設策略的。
/// <summary>
/// A provider of <see cref="ObjectPool{T}"/> instances.
/// </summary>
public abstract class ObjectPoolProvider
{
/// <summary>
/// Creates an <see cref="ObjectPool"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public ObjectPool<T> Create<T>() where T : class, new()
{
return Create<T>(new DefaultPooledObjectPolicy<T>());
}
/// <summary>
/// Creates an <see cref="ObjectPool"/> with the given <see cref="IPooledObjectPolicy{T}"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public abstract ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T : class;
}
IPooledObjectPolicy
IPooledObjectPolicy是一個泛型介面,提供策略管理對象池,該類也定義了兩個方法Create和Return以提供策略實現
- Create用於創建相關的類實例
- Return用於將已經使用完的對象放回到池中,包括重置對象狀態以及是否能夠放回到池中
/// <summary>
/// Represents a policy for managing pooled objects.
/// </summary>
/// <typeparam name="T">The type of object which is being pooled.</typeparam>
public interface IPooledObjectPolicy<T>
{
/// <summary>
/// Create a <typeparamref name="T"/>.
/// </summary>
/// <returns>The <typeparamref name="T"/> which was created.</returns>
T Create();
/// <summary>
/// Runs some processing when an object was returned to the pool. Can be used to reset the state of an object and indicate if the object should be returned to the pool.
/// </summary>
/// <param name="obj">The object to return to the pool.</param>
/// <returns><code>true</code> if the object should be returned to the pool. <code>false</code> if it's not possible/desirable for the pool to keep the object.</returns>
bool Return(T obj);
}
PooledObjectPolicy是一個泛型抽象類,並且實現了IPooledObjectPolicy,對外提供了兩個抽象方法
public abstract class PooledObjectPolicy<T> : IPooledObjectPolicy<T>
{
public abstract T Create();
public abstract bool Return(T obj);
}
實現機制
DefaultObjectPool
DefaultObjectPool實現了ObjectPool,Interlocked.CompareExchange(ref _firstItem, null, item)將_firstItem的值和item的值比較,相等則用null替換_firstItem,否則不操作,不管替換還是不替換返回的都是原來保存在_firstItem的值。
Interlocked可以為多個線程共用的變數提供原子操作。
- Interlocked.Increment:以原子操作的形式遞增指定變數的值並存儲結果。
- Interlocked.Decrement以原子操作的形式遞減指定變數的值並存儲結果。
- Interlocked.Add以原子操作的形式,添加兩個整數並用兩者的和替換第一個整數
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
{
}
}
}
}
DefaultObjectPoolProvider
DefaultObjectPoolProvider重寫了ObjectPoolProvider中Crearte方法,
設置了預設的對象最大數量只能用的是預設的Environment.ProcessorCount * 2(CPU處理器的兩倍)
/// <summary>
/// The default <see cref="ObjectPoolProvider"/>.
/// </summary>
public class DefaultObjectPoolProvider : ObjectPoolProvider
{
/// <summary>
/// The maximum number of objects to retain in the pool.
/// </summary>
public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2;
/// <inheritdoc/>
public override ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
if (typeof(IDisposable).IsAssignableFrom(typeof(T)))
{
return new DisposableObjectPool<T>(policy, MaximumRetained);
}
return new DefaultObjectPool<T>(policy, MaximumRetained);
}
}
DisposableObjectPool
DisposableObjectPool繼承了DefaultObjectPool以及實現了IDisposable用於手動的回收對象
public void Dispose()
{
_isDisposed = true;
DisposeItem(_firstItem);
_firstItem = null;
ObjectWrapper[] items = _items;
for (var i = 0; i < items.Length; i++)
{
DisposeItem(items[i].Element);
items[i].Element = null;
}
}
private void DisposeItem(T item)
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
LeakTrackingObjectPool
LeakTrackingObjectPool實現了ObjectPool,它定義了ConditionalWeakTable他是一個弱引用字典,ConditionalWeakTable<TKey,TValue> 中的所有 Key 和所有的 Value 都是弱引用的,並且會在其 Key 被回收或者 Key 和 Value 都被回收之後自動從集合中消失。這意味著當你使用它來為一個類型附加一些欄位或者屬性的時候完全不用擔心記憶體泄漏的問題
public class LeakTrackingObjectPool<T> : ObjectPool<T> where T : class
{
private readonly ConditionalWeakTable<T, Tracker> _trackers = new ConditionalWeakTable<T, Tracker>();
private readonly ObjectPool<T> _inner;
public LeakTrackingObjectPool(ObjectPool<T> inner)
{
if (inner == null)
{
throw new ArgumentNullException(nameof(inner));
}
_inner = inner;
}
public override T Get()
{
var value = _inner.Get();
_trackers.Add(value, new Tracker());
return value;
}
public override void Return(T obj)
{
Tracker tracker;
if (_trackers.TryGetValue(obj, out tracker))
{
_trackers.Remove(obj);
tracker.Dispose();
}
_inner.Return(obj);
}
private class Tracker : IDisposable
{
private readonly string _stack;
private bool _disposed;
public Tracker()
{
_stack = Environment.StackTrace;
}
public void Dispose()
{
_disposed = true;
GC.SuppressFinalize(this);
}
~Tracker()
{
if (!_disposed && !Environment.HasShutdownStarted)
{
Debug.Fail($"{typeof(T).Name} was leaked. Created at: {Environment.NewLine}{_stack}");
}
}
}
}
參考
https://blog.walterlv.com/post/conditional-weak-table.html
https://www.cnblogs.com/edison0621/p/11747912.html