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


寫在前面

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

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的創建方式,一個是基於默認策略的,一個是基於用戶自定義策略的。

   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。

  • 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:  }

實現機制

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

以下為其邏輯圖:
objectpool3

DefaultObjectPool

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

以下為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:  }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM