.NET Core 3.0之深刻源碼理解ObjectPool(二)

寫在前面

前文主要介紹了ObjectPool的一些理論基礎,本文主要從源碼角度理解Microsoft.Extensions.ObjectPool是如何實現的。下圖爲其三大核心組件圖:html

objectpool2

核心組件

ObjectPool

ObjectPool是一個泛型抽象類,裏面只有兩個抽象方法,Get和Return。它從底層定義了最通常的接口。數組

  • Get方法用於從對象池獲取到可用對象,若是對象不可用則建立對象並返回出來
  • Return方法用戶將對象返回到對象池

源碼以下:安全

   1:  public abstract class ObjectPool<T> where T : class
   2:  {
   3:      /// <summary>
   4:      /// Gets an object from the pool if one is available, otherwise creates one.
   5:      /// </summary>
   6:      /// <returns>A <typeparamref name="T"/>.</returns>
   7:      public abstract T Get();
   8:   
   9:      /// <summary>
  10:      /// Return an object to the pool.
  11:      /// </summary>
  12:      /// <param name="obj">The object to add to the pool.</param>
  13:      public abstract void Return(T obj);
  14:  }

ObjectPoolProvider

ObjectPoolProvider也是抽象類,其內部內置了一個已經實現的Create泛型方法以及一個抽象Create方法,這表明兩種ObjectPool的建立方式,一個是基於默認策略的,一個是基於用戶自定義策略的。app

   1:  public abstract class ObjectPoolProvider
   2:  {
   3:      /// <summary>
   4:      /// Creates an <see cref="ObjectPool"/>.
   5:      /// </summary>
   6:      /// <typeparam name="T">The type to create a pool for.</typeparam>
   7:      public ObjectPool<T> Create<T>() where T : class, new()
   8:      {
   9:          return Create<T>(new DefaultPooledObjectPolicy<T>());
  10:      }
  11:   
  12:      /// <summary>
  13:      /// Creates an <see cref="ObjectPool"/> with the given <see cref="IPooledObjectPolicy{T}"/>.
  14:      /// </summary>
  15:      /// <typeparam name="T">The type to create a pool for.</typeparam>
  16:      public abstract ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T : class;
  17:  }

IPooledObjectPolicy

這個接口是一個泛型接口,用於提供一種策略來管理對象池中的對象,一樣也有兩個方法,Create和Return。ide

  • Create方法用於建立相關類型實例
  • Return方法用於將已經使用好的對象放回到對象池的時候進行邏輯處理,包括對象的狀態重置以及是否可以放回到對象池
   1:  public interface IPooledObjectPolicy<T>
   2:  {
   3:      /// <summary>
   4:      /// Create a <typeparamref name="T"/>.
   5:      /// </summary>
   6:      /// <returns>The <typeparamref name="T"/> which was created.</returns>
   7:      T Create();
   8:   
   9:      /// <summary>
  10:      /// 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.
  11:      /// </summary>
  12:      /// <param name="obj">The object to return to the pool.</param>
  13:      /// <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>
  14:      bool Return(T obj);
  15:  }

該接口有一個實現PooledObjectPolicy,這是一個抽象類,內部有兩個抽象方法:函數

   1:  public abstract class PooledObjectPolicy<T> : IPooledObjectPolicy<T>
   2:  {
   3:      public abstract T Create();
   4:   
   5:      public abstract bool Return(T obj);
   6:  }

實現機制

其內部實現邏輯較爲簡單,充分考慮到了通常實現、對象追蹤、對象釋放等場景的使用方式。ui

如下爲其邏輯圖:
objectpool3this

DefaultObjectPool

DefaultObjectPool實現了ObjectPool,其內部維護了一個結構體類型的私有數組,用於存儲相關對象。該數組的大小在構造函數中定義,其實際大小爲輸入值減去1(默認狀況下,其值爲邏輯處理器數量的兩倍)主要是由於DefaultObjectPool單獨將首項定義了出來。spa

如下爲DefaultObjectPool中Get和Return的實現:線程

   1:  public override T Get()
   2:  {
   3:      var item = _firstItem;
   4:      if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
   5:      {
   6:          var items = _items;
   7:          for (var i = 0; i < items.Length; i++)
   8:          {
   9:              item = items[i].Element;
  10:              if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
  11:              {
  12:                  return item;
  13:              }
  14:          }
  15:   
  16:          item = Create();
  17:      }
  18:   
  19:      return item;
  20:  }
  21:   
  22:  public override void Return(T obj)
  23:  {
  24:      if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
  25:      {
  26:          if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
  27:          {
  28:              var items = _items;
  29:              for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
  30:              {
  31:              }
  32:          }
  33:      }
  34:  }

經過源碼能夠知道這兩個方法大量使用了Interlocked.CompareExchange:

   1:  public static int CompareExchange(
   2:      ref int location1,
   3:      int value,
   4:      int comparand
   5:  )

比較location1與comparand,若是不相等,什麼都不作;若是location1與comparand相等,則用value替換location1的值。不管比較結果相等與否,返回值都是location1中原有的值。

Interlocked.CompareExchange的使用確保了線程安全性。

DefaultObjectPoolProvider

DefaultObjectPoolProvider實現了ObjectPoolProvider,該類重寫了Create方法並返回ObjectPool對象。該類還定義了MaximumRetained屬性,默認狀況下,其值爲邏輯處理器數量的兩倍。

其源碼以下,比較簡單:

   1:  public class DefaultObjectPoolProvider : ObjectPoolProvider
   2:  {
   3:      /// <summary>
   4:      /// The maximum number of objects to retain in the pool.
   5:      /// </summary>
   6:      public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2;
   7:   
   8:      /// <inheritdoc/>
   9:      public override ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy)
  10:      {
  11:          if (policy == null)
  12:          {
  13:              throw new ArgumentNullException(nameof(policy));
  14:          }
  15:   
  16:          if (typeof(IDisposable).IsAssignableFrom(typeof(T)))
  17:          {
  18:              return new DisposableObjectPool<T>(policy, MaximumRetained);
  19:          }
  20:   
  21:          return new DefaultObjectPool<T>(policy, MaximumRetained);
  22:      }
  23:  }

其中DisposableObjectPool是DefaultObjectPool類的派生類,這個類也實現了IDisposable,用於建立可手動釋放的ObjectPool對象。

其相關代碼以下:

   1:  public void Dispose()
   2:  {
   3:      _isDisposed = true;
   4:   
   5:      DisposeItem(_firstItem);
   6:      _firstItem = null;
   7:   
   8:      ObjectWrapper[] items = _items;
   9:      for (var i = 0; i < items.Length; i++)
  10:      {
  11:          DisposeItem(items[i].Element);
  12:          items[i].Element = null;
  13:      }
  14:  }
  15:   
  16:  private void DisposeItem(T item)
  17:  {
  18:      if (item is IDisposable disposable)
  19:      {
  20:          disposable.Dispose();
  21:      }
  22:  }

DefaultPooledObjectPolicy

該類繼承了PooledObjectPolicy,實現也很是簡單。

不過值得注意的是,PooledObjectPolicy還有一個實現StringBuilderPooledObjectPolicy,這個類從命名上看就知道是基於StringBuilder的。其內部默認定義了StringBuilder的大小以及初始化容量。並肯定了超出容量後,將不容許歸還對象。

在咱們自定義PooledObjectPolicy的時候,能夠參考這段實現去擴展新的PooledObjectPolicy對象。

咱們看一下源碼:

   1:  public class StringBuilderPooledObjectPolicy : PooledObjectPolicy<StringBuilder>
   2:  {
   3:      public int InitialCapacity { get; set; } = 100;
   4:   
   5:      public int MaximumRetainedCapacity { get; set; } = 4 * 1024;
   6:   
   7:      public override StringBuilder Create()
   8:      {
   9:          return new StringBuilder(InitialCapacity);
  10:      }
  11:   
  12:      public override bool Return(StringBuilder obj)
  13:      {
  14:          if (obj.Capacity > MaximumRetainedCapacity)
  15:          {
  16:              // Too big. Discard this one.
  17:              return false;
  18:          }
  19:   
  20:          obj.Clear();
  21:          return true;
  22:      }
  23:  }

對象追蹤

該庫內部定義了LeakTrackingObjectPool和LeakTrackingObjectPoolProvider用於追蹤對象狀態。

  • LeakTrackingObjectPoolProvider會根據構造函數傳入的ObjectPoolProvider類型對象,建立LeakTrackingObjectPool實例。
  • LeakTrackingObjectPool內部定義了ConditionalWeakTable<T, Tracker>類型的數組,MSDN的解釋是使編譯器能夠將對象字段動態附加到託管對象,這個對象會自動維護內部的鍵值對,而不會一直使其停留在內存中。

Tracker是LeakTrackingObjectPool的內部類,其目的是爲了方便咱們對對象自己進行維護跟蹤,其定義以下:

   1:  private class Tracker : IDisposable
   2:  {
   3:      private readonly string _stack;
   4:      private bool _disposed;
   5:   
   6:      public Tracker()
   7:      {
   8:          _stack = Environment.StackTrace;
   9:      }
  10:   
  11:      public void Dispose()
  12:      {
  13:          _disposed = true;
  14:          GC.SuppressFinalize(this);
  15:      }
  16:   
  17:      ~Tracker()
  18:      {
  19:          if (!_disposed && !Environment.HasShutdownStarted)
  20:          {
  21:              Debug.Fail($"{typeof(T).Name} was leaked. Created at: {Environment.NewLine}{_stack}");
  22:          }
  23:      }
  24:  }
相關文章
相關標籤/搜索