/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs
155 строк
5 KB
Cyrus Najmabadi
Use implicit object creation expressions
13 сен 2025, 01:48
13 сен 2025, 01:48
4c6a36a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; namespace Roslyn.VisualStudio.DiagnosticsWindow.OptionsPages; internal sealed class ForceLowMemoryMode { public static readonly Option2<bool> Enabled = new("ForceLowMemoryMode_Enabled", defaultValue: false); public static readonly Option2<int> SizeInMegabytes = new("ForceLowMemoryMode_Enabled", defaultValue: 500); private readonly IGlobalOptionService _globalOptions; private MemoryHogger? _hogger; public ForceLowMemoryMode(IGlobalOptionService globalOptions) { _globalOptions = globalOptions; globalOptions.AddOptionChangedHandler(this, Options_OptionChanged); RefreshFromSettings(); } private void Options_OptionChanged(object sender, object target, OptionChangedEventArgs e) { if (e.HasOption(static option => option.Equals(Enabled) || option.Equals(SizeInMegabytes))) { RefreshFromSettings(); } } private void RefreshFromSettings() { var enabled = _globalOptions.GetOption(Enabled); if (_hogger != null) { _hogger.Cancel(); _hogger = null; } if (enabled) { _hogger = new MemoryHogger(); _ = _hogger.PopulateAndMonitorAsync(_globalOptions.GetOption(SizeInMegabytes)); } } private sealed class MemoryHogger { private const int BlockSize = 1024 * 1024; // megabyte blocks private const int MonitorDelay = 10000; // 10 seconds private readonly List<byte[]> _blocks = []; private readonly CancellationTokenSource _cancellationTokenSource = new(); public MemoryHogger() { } public int Count { get { return _blocks.Count; } } public void Cancel() { _cancellationTokenSource.Cancel(); } public Task PopulateAndMonitorAsync(int size) { // run on background thread return Task.Factory.StartNew(() => this.PopulateAndMonitorWorkerAsync(size), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap(); } private async Task PopulateAndMonitorWorkerAsync(int size) { try { try { for (var n = 0; n < size; n++) { _cancellationTokenSource.Token.ThrowIfCancellationRequested(); var block = new byte[BlockSize]; // initialize block bits (so the memory actually gets allocated.. silly runtime!) for (var i = 0; i < BlockSize; i++) { block[i] = 0xFF; } _blocks.Add(block); // don't hog the thread await Task.Yield(); } } catch (OutOfMemoryException) { } // monitor memory to keep it paged in while (true) { _cancellationTokenSource.Token.ThrowIfCancellationRequested(); try { // access all block bytes for (var b = 0; b < _blocks.Count; b++) { _cancellationTokenSource.Token.ThrowIfCancellationRequested(); var block = _blocks[b]; byte tmp; for (var i = 0; i < block.Length; i++) { tmp = block[i]; } // don't hog the thread await Task.Yield(); } } catch (OutOfMemoryException) { } await Task.Delay(MonitorDelay, _cancellationTokenSource.Token).ConfigureAwait(false); } } catch (OperationCanceledException) { _blocks.Clear(); // force garbage collection for (var i = 0; i < 5; i++) { GC.Collect(GC.MaxGeneration); GC.WaitForPendingFinalizers(); } } } } }