private ObjectPoolSegment <T> CreateSegment(bool allowSegmentToBeCleanedUp) { if (_disposed) { throw new ObjectDisposedException("ObjectPoolBase"); } // This method is called inside a lock, so no interlocked stuff required. int segmentToAdd = _activeSegment; _activeSegment++; Queue <T> buffers = new Queue <T>(); for (int i = 1; i <= this._itemsPerSegment; i++) { T obj = GetObjectInstance(); buffers.Enqueue(obj); } // certain segments we don't want to ever be cleaned up (the initial segments) DateTime cleanupTime = (allowSegmentToBeCleanedUp) ? DateTime.Now.Add(this._minimumAgeToCleanup) : DateTime.MaxValue; ObjectPoolSegment <T> segment = new ObjectPoolSegment <T>(segmentToAdd, buffers, cleanupTime); return(segment); }
/// <summary> /// Checks in an instance of T owned by the object pool. This method is only intended to be called /// by the <c>WrappedObject</c> class. /// </summary> /// <param name="owningSegment">The segment from which the instance is checked out.</param> /// <param name="instance">The instance of <c>T</c> to check back into the segment.</param> internal void CheckIn(ObjectPoolSegment <T> owningSegment, T instance) { lock (_syncRoot) { owningSegment.CheckInObject(instance); } }
protected void Initialize(int itemsPerSegment, int minimumSegmentCount, bool gcOnPoolGrowth, int cleanupFrequenceMS) { _itemsPerSegment = itemsPerSegment; _minimumSegmentCount = minimumSegmentCount; _gc = gcOnPoolGrowth; // force garbage collection to make sure these new long lived objects // cause as little fragmentation as possible if (_gc) { System.GC.Collect(); } lock (_syncRoot) { while (_segments.Count < this.MinimumSegmentCount) { ObjectPoolSegment <T> segment = CreateSegment(false); _segments.Add(segment.SegmentNumber, segment); } } // This forces a compact, to make sure our objects fill in any holes in the heap. if (_gc) { System.GC.Collect(); } _timer = new Timer(CleanupThreadCallback, null, cleanupFrequenceMS, cleanupFrequenceMS); }
/// <summary> /// Checks an instance of <c>T</c> from the pool. If the pool is not sufficient to /// allow the checkout, a new segment is created. /// </summary> /// <returns>A <c>WrappedObject</c> around the instance of <c>T</c>. To check /// the instance back into the segment, be sureto dispose the WrappedObject /// when finished. </returns> public WrappedObject <T> CheckOut() { if (_disposed) { throw new ObjectDisposedException("ObjectPoolBase"); } // It's key that this CheckOut always, always, uses a pooled object // from the oldest available segment. This will help keep the "newer" // segments from being used - which in turn, makes them eligible // for deletion. lock (_syncRoot) { ObjectPoolSegment <T> targetSegment = null; // find the oldest segment that has items available for checkout for (int i = 0; i < _activeSegment; i++) { ObjectPoolSegment <T> segment; if (_segments.TryGetValue(i, out segment) == true) { if (segment.AvailableItems > 0) { targetSegment = segment; break; } } } if (targetSegment == null) { // We couldn't find a sigment that had any available space in it, // so it's time to create a new segment. // Before creating the segment, do a GC to make sure the heap // is compacted. if (_gc) { GC.Collect(); } targetSegment = CreateSegment(true); if (_gc) { GC.Collect(); } _segments.Add(targetSegment.SegmentNumber, targetSegment); } WrappedObject <T> obj = new WrappedObject <T>(this, targetSegment, targetSegment.CheckOutObject()); return(obj); } }
internal WrappedObject(ObjectPoolBase <T> owningPool, ObjectPoolSegment <T> ownerSegment, T activeInstance) { _owningObjectPool = owningPool; _owningSegment = ownerSegment; _instance = activeInstance; }