示例#1
0
        /// <summary>
        /// Register a notification to occur *AFTER* a GC occurs in which the memory load changes from within the bound specified
        /// to outside of the bound specified. This notification will occur once. If repeated notifications are required, the notification
        /// must be reregistered. The notification will occur on a thread which should not be blocked. Complex processing in the notification should defer work to the threadpool.
        /// </summary>
        /// <param name="lowMemoryPercent">percent of HighMemoryLoadThreshold to use as lower bound. Must be a number >= 0 or an ArgumentOutOfRangeException will be thrown.</param>
        /// <param name="highMemoryPercent">percent of HighMemoryLoadThreshold use to use as lower bound. Must be a number > lowMemory or an ArgumentOutOfRangeException will be thrown. </param>
        /// <param name="notification">delegate to invoke when operation occurs</param>s
        internal static void RegisterMemoryLoadChangeNotification(float lowMemoryPercent, float highMemoryPercent, Action notification)
        {
            if (highMemoryPercent < 0 || highMemoryPercent > 1.0 || highMemoryPercent <= lowMemoryPercent)
            {
                throw new ArgumentOutOfRangeException(nameof(highMemoryPercent));
            }
            if (lowMemoryPercent < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(lowMemoryPercent));
            }
            if (notification == null)
            {
                throw new ArgumentNullException(nameof(notification));
            }

            lock (s_notifications)
            {
                s_notifications.Add(new MemoryLoadChangeNotification(lowMemoryPercent, highMemoryPercent, notification));

                if (s_notifications.Count == 1)
                {
                    Gen2GcCallback.Register(InvokeMemoryLoadChangeNotifications);
                }
            }
        }
        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 (_freeList.TryPop(out returnBuffer))
                {
                    return;
                }

                // Lazy init, Ask that TrimFreeListIfNeeded be called on every Gen 2 GC.
                if (_restockSize == 0)
                {
                    Gen2GcCallback.Register(Gen2GcCallbackFunc, this);
                }

                // Indicate to the trimming policy that the free list is insufficient.
                _moreThanFreeListNeeded = true;
                PinnableBufferCacheEventSource.Log.AllocateBufferFreeListEmpty(_cacheName, _notGen2.Count);

                // Get more buffers if needed.
                if (_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(_notGen2.Count != 0);
                int idx = _notGen2.Count - 1;
                if (GC.GetGeneration(_notGen2[idx]) < GC.MaxGeneration && GC.GetGeneration(_notGen2[0]) == GC.MaxGeneration)
                {
                    idx = 0;
                }

                returnBuffer = _notGen2[idx];
                _notGen2.RemoveAt(idx);

                // Remember any sub-optimal 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(_cacheName, _notGen2.Count);
                }

                // If we have a Gen1 collection, then everything on _notGen2 should have aged.  Move them to the _freeList.
                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 (_notGen2.Count == _restockSize / 2)
                    {
                        PinnableBufferCacheEventSource.Log.DebugMessage("Proactively adding more buffers to aging pool");
                        CreateNewBuffers();
                    }
                }
            }
        }