internal void Free(object buffer) { if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.FreeBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), _freeList.Count); } // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. if ((_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) { lock (this) { if (GC.GetGeneration(buffer) < GC.MaxGeneration) { // The buffer is not aged, so put it in the non-aged free list. _moreThanFreeListNeeded = true; PinnableBufferCacheEventSource.Log.FreeBufferStillTooYoung(_cacheName, _notGen2.Count); _notGen2.Add(buffer); _gen1CountAtLastRestock = GC.CollectionCount(GC.MaxGeneration - 1); return; } } } // If we discovered that it is indeed Gen2, great, put it in the Gen2 list. _freeList.Push(buffer); }
internal object Allocate() { // Fast path, get it from our Gen2 aged _freeList. object returnBuffer; if (!_freeList.TryPop(out returnBuffer)) { Restock(out returnBuffer); } // Computing free count is expensive enough that we don't want to compute it unless logging is on. if (PinnableBufferCacheEventSource.Log.IsEnabled()) { int numAllocCalls = Interlocked.Increment(ref _numAllocCalls); if (numAllocCalls >= 1024) { lock (this) { int previousNumAllocCalls = Interlocked.Exchange(ref _numAllocCalls, 0); if (previousNumAllocCalls >= 1024) { int nonGen2Count = 0; foreach (object o in _freeList) { if (GC.GetGeneration(o) < GC.MaxGeneration) { nonGen2Count++; } } PinnableBufferCacheEventSource.Log.WalkFreeListResult(_cacheName, _freeList.Count, nonGen2Count); } } } PinnableBufferCacheEventSource.Log.AllocateBuffer(_cacheName, PinnableBufferCacheEventSource.AddressOf(returnBuffer), returnBuffer.GetHashCode(), GC.GetGeneration(returnBuffer), _freeList.Count); } return(returnBuffer); }