/// <summary> /// Call this method to suppress expensive blocking Gen 2 garbage GCs in /// scenarios where high-latency is unacceptable (e.g. processing typing input). /// /// Blocking GCs will be re-enabled automatically after a short duration unless /// UseLowLatencyModeForProcessingUserInput is called again. /// </summary> internal static void UseLowLatencyModeForProcessingUserInput() { if (s_delayMilliseconds <= 0) { // The registry key to opt out of Roslyn's SustainedLowLatency is set, or // we haven't yet initialized the value. return; } var currentMode = GCSettings.LatencyMode; var currentDelay = s_delay; if (currentMode != GCLatencyMode.SustainedLowLatency) { GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; // Restore the LatencyMode a short duration after the // last request to UseLowLatencyModeForProcessingUserInput. currentDelay = new ResettableDelay(s_delayMilliseconds); currentDelay.Task.SafeContinueWith(_ => RestoreGCLatencyMode(currentMode), TaskScheduler.Default); s_delay = currentDelay; } if (currentDelay != null) { currentDelay.Reset(); } }
private static void RestoreGCLatencyMode(GCLatencyMode originalMode) { GCSettings.LatencyMode = originalMode; s_delay = null; // hint to the GC that if it postponed a gen 2 collection, now might be a good time to do it. GC.Collect(2, GCCollectionMode.Optimized); }
private void EnqueueUpdate() { const int WorkspaceUpdateDelay = 1500; var delay = _delay; if (delay == null) { var newDelay = new ResettableDelay(WorkspaceUpdateDelay); if (Interlocked.CompareExchange(ref _delay, newDelay, null) == null) { var asyncToken = _asyncListener.BeginAsyncOperation("WorkspaceGraphQueryManager.EnqueueUpdate"); newDelay.Task.SafeContinueWithFromAsync(_ => UpdateAsync(), CancellationToken.None, TaskScheduler.Default) .CompletesAsyncOperation(asyncToken); } return; } delay.Reset(); }
private void PostUpdate(Solution solution) { _delay = null; lock (_gate) { // See if each context is still alive. It's possible it's already been GC'ed meaning we should stop caring about the query _trackedQueries.RemoveAll(t => !IsTrackingContext(t.Item1)); if (_trackedQueries.IsEmpty()) { _workspace.WorkspaceChanged -= OnWorkspaceChanged; return; } } EnqueueUpdateIfSolutionIsStale(solution); }