| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System.Collections.Generic;
- using System.Runtime;
- // This is the base object pool class which manages objects in a FIFO queue. The objects are
- // created through the provided Func<T> createObjectFunc. The main purpose for this class is
- // to get better memory usage for Garbage Collection (GC) when part or all of an object is
- // regularly pinned. Constantly creating such objects can cause large Gen0 Heap fragmentation
- // and thus high memory usage pressure. The pooled objects are first created in Gen0 heaps and
- // would be eventually moved to a more stable segment which would prevent the fragmentation
- // to happen.
- //
- // The objects are created in batches for better localization of the objects. Here are the
- // parameters that control the behavior of creation/removal:
- //
- // batchAllocCount: number of objects to be created at the same time when new objects are needed
- //
- // createObjectFunc: func delegate that is used to create objects by sub-classes.
- //
- // maxFreeCount: max number of free objects the queue can store. This is to make sure the memory
- // usage is bounded.
- //
- abstract class QueuedObjectPool<T>
- {
- Queue<T> objectQueue;
- bool isClosed;
- int batchAllocCount;
- int maxFreeCount;
- protected void Initialize(int batchAllocCount, int maxFreeCount)
- {
- if (batchAllocCount <= 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("batchAllocCount"));
- }
- Fx.Assert(batchAllocCount <= maxFreeCount, "batchAllocCount cannot be greater than maxFreeCount");
- this.batchAllocCount = batchAllocCount;
- this.maxFreeCount = maxFreeCount;
- this.objectQueue = new Queue<T>(batchAllocCount);
- }
- object ThisLock
- {
- get
- {
- return this.objectQueue;
- }
- }
- public virtual bool Return(T value)
- {
- lock (ThisLock)
- {
- if (this.objectQueue.Count < this.maxFreeCount && ! this.isClosed)
- {
- this.objectQueue.Enqueue(value);
- return true;
- }
- return false;
- }
- }
- public T Take()
- {
- lock (ThisLock)
- {
- Fx.Assert(!this.isClosed, "Cannot take an item from closed QueuedObjectPool");
- if (this.objectQueue.Count == 0)
- {
- AllocObjects();
- }
- return this.objectQueue.Dequeue();
- }
- }
- public void Close()
- {
- lock (ThisLock)
- {
- foreach (T item in this.objectQueue)
- {
- if (item != null)
- {
- this.CleanupItem(item);
- }
- }
- this.objectQueue.Clear();
- this.isClosed = true;
- }
- }
- protected virtual void CleanupItem(T item)
- {
- }
- protected abstract T Create();
- void AllocObjects()
- {
- Fx.Assert(this.objectQueue.Count == 0, "The object queue must be empty for new allocations");
- for (int i = 0; i < batchAllocCount; i++)
- {
- this.objectQueue.Enqueue(Create());
- }
- }
- }
- }
|