QueuedObjectPool.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections.Generic;
  7. using System.Runtime;
  8. // This is the base object pool class which manages objects in a FIFO queue. The objects are
  9. // created through the provided Func<T> createObjectFunc. The main purpose for this class is
  10. // to get better memory usage for Garbage Collection (GC) when part or all of an object is
  11. // regularly pinned. Constantly creating such objects can cause large Gen0 Heap fragmentation
  12. // and thus high memory usage pressure. The pooled objects are first created in Gen0 heaps and
  13. // would be eventually moved to a more stable segment which would prevent the fragmentation
  14. // to happen.
  15. //
  16. // The objects are created in batches for better localization of the objects. Here are the
  17. // parameters that control the behavior of creation/removal:
  18. //
  19. // batchAllocCount: number of objects to be created at the same time when new objects are needed
  20. //
  21. // createObjectFunc: func delegate that is used to create objects by sub-classes.
  22. //
  23. // maxFreeCount: max number of free objects the queue can store. This is to make sure the memory
  24. // usage is bounded.
  25. //
  26. abstract class QueuedObjectPool<T>
  27. {
  28. Queue<T> objectQueue;
  29. bool isClosed;
  30. int batchAllocCount;
  31. int maxFreeCount;
  32. protected void Initialize(int batchAllocCount, int maxFreeCount)
  33. {
  34. if (batchAllocCount <= 0)
  35. {
  36. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("batchAllocCount"));
  37. }
  38. Fx.Assert(batchAllocCount <= maxFreeCount, "batchAllocCount cannot be greater than maxFreeCount");
  39. this.batchAllocCount = batchAllocCount;
  40. this.maxFreeCount = maxFreeCount;
  41. this.objectQueue = new Queue<T>(batchAllocCount);
  42. }
  43. object ThisLock
  44. {
  45. get
  46. {
  47. return this.objectQueue;
  48. }
  49. }
  50. public virtual bool Return(T value)
  51. {
  52. lock (ThisLock)
  53. {
  54. if (this.objectQueue.Count < this.maxFreeCount && ! this.isClosed)
  55. {
  56. this.objectQueue.Enqueue(value);
  57. return true;
  58. }
  59. return false;
  60. }
  61. }
  62. public T Take()
  63. {
  64. lock (ThisLock)
  65. {
  66. Fx.Assert(!this.isClosed, "Cannot take an item from closed QueuedObjectPool");
  67. if (this.objectQueue.Count == 0)
  68. {
  69. AllocObjects();
  70. }
  71. return this.objectQueue.Dequeue();
  72. }
  73. }
  74. public void Close()
  75. {
  76. lock (ThisLock)
  77. {
  78. foreach (T item in this.objectQueue)
  79. {
  80. if (item != null)
  81. {
  82. this.CleanupItem(item);
  83. }
  84. }
  85. this.objectQueue.Clear();
  86. this.isClosed = true;
  87. }
  88. }
  89. protected virtual void CleanupItem(T item)
  90. {
  91. }
  92. protected abstract T Create();
  93. void AllocObjects()
  94. {
  95. Fx.Assert(this.objectQueue.Count == 0, "The object queue must be empty for new allocations");
  96. for (int i = 0; i < batchAllocCount; i++)
  97. {
  98. this.objectQueue.Enqueue(Create());
  99. }
  100. }
  101. }
  102. }