/// <summary> /// Schedule 'callback' to be called in the next GC. If the callback returns true it is /// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop. /// /// NOTE: This callback will be kept alive until either the callback function returns false, /// or the target object dies. /// </summary> public static void Register(Func <object, bool> callback, object targetObj) { // Create a unreachable object that remembers the callback function and target object. Gen2GcCallback gcCallback = new Gen2GcCallback(); gcCallback.Setup(callback, targetObj); }
private void Restock(out object returnBuffer) { lock (this) { // Try again after getting the lock as another thread could have just filled the free list. If we don't check // then we unnecessarily grab a new set of buffers because we think we are out. if (m_FreeList.TryPop(out returnBuffer)) { return; } // Lazy init, Ask that TrimFreeListIfNeeded be called on every Gen 2 GC. if (m_restockSize == 0) { Gen2GcCallback.Register(Gen2GcCallbackFunc, this); } // Indicate to the trimming policy that the free list is insufficent. m_moreThanFreeListNeeded = true; PinnableBufferCacheEventSource.Log.AllocateBufferFreeListEmpty(m_CacheName, m_NotGen2.Count); // Get more buffers if needed. if (m_NotGen2.Count == 0) { CreateNewBuffers(); } // We have no buffers in the aged freelist, so get one from the newer list. Try to pick the best one. // Debug.Assert(m_NotGen2.Count != 0); int idx = m_NotGen2.Count - 1; if (GC.GetGeneration(m_NotGen2[idx]) < GC.MaxGeneration && GC.GetGeneration(m_NotGen2[0]) == GC.MaxGeneration) { idx = 0; } returnBuffer = m_NotGen2[idx]; m_NotGen2.RemoveAt(idx); // Remember any sub-optimial buffer so we don't put it on the free list when it gets freed. if (PinnableBufferCacheEventSource.Log.IsEnabled() && GC.GetGeneration(returnBuffer) < GC.MaxGeneration) { PinnableBufferCacheEventSource.Log.AllocateBufferFromNotGen2(m_CacheName, m_NotGen2.Count); } // If we have a Gen1 collection, then everything on m_NotGen2 should have aged. Move them to the m_Free list. if (!AgePendingBuffers()) { // Before we could age at set of buffers, we have handed out half of them. // This implies we should be proactive about allocating more (since we will trim them if we over-allocate). if (m_NotGen2.Count == m_restockSize / 2) { PinnableBufferCacheEventSource.Log.DebugMessage("Proactively adding more buffers to aging pool"); CreateNewBuffers(); } } } }