示例#1
0
            private bool AlertProxyMonitors(long current, long limit, RecycleLimitNotificationFrequency frequency)
            {
                bool requestGC = false;

                KeyValuePair <RecycleLimitMonitor, string>[] proxies = null;

                lock (this) {
                    if (_proxyMonitors.Count == 0)
                    {
                        StopTimer();
                        return(requestGC);
                    }

                    proxies = _proxyMonitors.ToArray <KeyValuePair <RecycleLimitMonitor, string> >();
                }

                foreach (KeyValuePair <RecycleLimitMonitor, string> pair in proxies)
                {
                    try {
                        var ac = _appManager.GetLockableAppDomainContext(pair.Value);
                        if (ac != null)
                        {
                            lock (ac) {
                                requestGC |= pair.Key.RaiseRecycleLimitEvent(current, limit, frequency);
                            }
                        }
                    }
                    catch (Exception e) {
                        // Unhandled Exceptions here will crash the process
                        Misc.ReportUnhandledException(e, new string[] { SR.GetString(SR.Unhandled_Monitor_Exception, "RaiseRecycleLimitEvent", "RecycleLimitMonitor") });
                    }
                }

                return(requestGC);
            }
示例#2
0
        internal bool RaiseRecycleLimitEvent(long current, long limit, RecycleLimitNotificationFrequency frequency)
        {
            RecycleLimitInfo info = new RecycleLimitInfo(current, limit, frequency);

            IObserver <RecycleLimitInfo>[] observers;

            if (_isStarted)
            {
                lock (_observers) {
                    observers = _observers.ToArray();
                }

                foreach (IObserver <RecycleLimitInfo> obs in observers)
                {
                    try {
                        obs.OnNext(info);
                    }
                    catch (Exception e) {
                        // Unhandled Exceptions here will crash the process
                        Misc.ReportUnhandledException(e, new string[] { SR.GetString(SR.Unhandled_Monitor_Exception, "RaiseRecycleLimitEvent", "RecycleLimitMonitor") });
                    }
                }

                return(info.RequestGC);
            }

            return(false);
        }
示例#3
0
 public RecycleLimitInfo(long currentPrivateBytes, long recycleLimit, RecycleLimitNotificationFrequency recycleLimitNearFrequency)
 {
     _currentPB    = currentPrivateBytes;
     _recycleLimit = recycleLimit;
     _recycleLimitNearFrequency = recycleLimitNearFrequency;
     _requestGC = false;
 }
示例#4
0
            private void CollectInfrequently(long privateBytes)
            {
                // not thread-safe, only invoke from timer callback
                Debug.Assert(_inPBytesMonitorThread == 1);

                // The Server GC on x86 can traverse ~200mb per CPU per second, and the maximum heap size
                // is about 3400mb, so the worst case scenario on x86 would take about 8 seconds to collect
                // on a dual CPU box.
                //
                // The Server GC on x64 can traverse ~300mb per CPU per second, so a 6000 MB heap will take
                // about 10 seconds to collect on a dual CPU box.  The worst case scenario on x64 would make
                // you want to return your hardware for a refund.

                long timeSinceInducedGC = DateTime.UtcNow.Subtract(_inducedGCFinishTime).Ticks;
                bool infrequent         = (timeSinceInducedGC > _inducedGCMinInterval);
                RecycleLimitNotificationFrequency frequency = RecycleLimitNotificationFrequency.Medium;

                // if we haven't collected recently, or if the trim percent is low (less than 50%),
                // we need to collect again
                if (infrequent || _howFrequent < 5)
                {
                    // if we're inducing GC too frequently, increase the trim percentage, but don't go above 50%
                    if (!infrequent)
                    {
                        _howFrequent = Math.Min(5, _howFrequent + 1);
                        frequency    = RecycleLimitNotificationFrequency.High;
                    }
                    // if we're inducing GC infrequently, we may want to decrease the trim percentage
                    else if (_howFrequent > 1 && timeSinceInducedGC > 2 * _inducedGCMinInterval)
                    {
                        _howFrequent = Math.Max(1, _howFrequent - 1);
                        frequency    = RecycleLimitNotificationFrequency.Low;
                    }

                    Stopwatch sw1       = Stopwatch.StartNew();
                    bool      requestGC = AlertProxyMonitors(privateBytes, _limit, frequency);
                    sw1.Stop();

                    //

                    if (!requestGC || _appManager.ShutdownInProgress)
                    {
                        return;
                    }

                    // collect and record statistics
                    Stopwatch sw2 = Stopwatch.StartNew();
                    GC.Collect();
                    sw2.Stop();

                    _inducedGCCount++; // only used for debugging
                    _inducedGCFinishTime         = DateTime.UtcNow;
                    _inducedGCDurationTicks      = sw2.Elapsed.Ticks;
                    _inducedGCPostPrivateBytes   = NextSample();
                    _inducedGCPrivateBytesChange = privateBytes - _inducedGCPostPrivateBytes;
                    // target 3.3% Time in GC, but don't induce a GC more than once every 5 seconds
                    // Notes on calculation below:  If G is duration of garbage collection and T is duration
                    // between starting the next collection, then G/T is % Time in GC.  If we target 3.3%,
                    // then G/T = 3.3% = 33/1000, so T = G * 1000/33.
                    _inducedGCMinInterval = Math.Max(_inducedGCDurationTicks * 1000 / 33, 5 * TimeSpan.TicksPerSecond);
                    // no more frequently than every 60 seconds if change is less than 1%
                    if (_inducedGCPrivateBytesChange * 100 <= privateBytes)
                    {
                        _inducedGCMinInterval = Math.Max(_inducedGCMinInterval, 60 * TimeSpan.TicksPerSecond);
                    }
#if DBG
                    Debug.Trace("RecycleLimitMonitorSingleton", "GC.COLLECT STATS "
                                + "TrimCaches(" + frequency + ")"
                                + ", trimDurationSeconds=" + (sw1.Elapsed.Ticks / TimeSpan.TicksPerSecond)
                                + ", requestGC=" + requestGC
                                + ", #secondsSinceInducedGC=" + (timeSinceInducedGC / TimeSpan.TicksPerSecond)
                                + ", InducedGCCount=" + _inducedGCCount
                                + ", gcDurationSeconds=" + (_inducedGCDurationTicks / TimeSpan.TicksPerSecond)
                                + ", PrePrivateBytes=" + privateBytes
                                + ", PostPrivateBytes=" + _inducedGCPostPrivateBytes
                                + ", PrivateBytesChange=" + _inducedGCPrivateBytesChange
                                + ", gcMinIntervalSeconds=" + (_inducedGCMinInterval / TimeSpan.TicksPerSecond));
#endif

#if PERF
                    SafeNativeMethods.OutputDebugString("  ** COLLECT **: "
                                                        + percent + "%, "
                                                        + (sw1.Elapsed.Ticks / TimeSpan.TicksPerSecond) + " seconds"
                                                        + ", infrequent=" + infrequent
                                                        + ", removed=" + trimmedOrExpired
                                                        + ", sinceIGC=" + (timeSinceInducedGC / TimeSpan.TicksPerSecond)
                                                        + ", IGCCount=" + _inducedGCCount
                                                        + ", IGCDuration=" + (_inducedGCDurationTicks / TimeSpan.TicksPerSecond)
                                                        + ", preBytes=" + privateBytes
                                                        + ", postBytes=" + _inducedGCPostPrivateBytes
                                                        + ", byteChange=" + _inducedGCPrivateBytesChange
                                                        + ", IGCMinInterval=" + (_inducedGCMinInterval / TimeSpan.TicksPerSecond) + "\n");
#endif
                }
            }