08.11.2009Эти прожорливые .NET приложения!
Изучая .NET Framework я решил написать простое приложение-украшательство в виде аналоговых часов на рабочий стол, и так, как предполагалось, что программа будет работать все время, пока загружена Windows было важно, чтобы она использовала как можно меньше системных ресурсов. Я открыл свою любимую Visual Studio 2008, скомпилировал и запустил пустой проект WinForms и что вы думаете я увидел в диспетчере задач? 20 мегабайт оперативной памяти занимала моя программа, и это без полезной нагрузки! Ну не фига себе пельмень, подумал я и начал искать решение.
Откуда такой аппетит.
Немного погуглив я выяснил, что на самом деле, это не память, фактически используемая приложением, а так называемое «рабочее множество». Если не вникать в теорию операционных систем, это память, зарезервированная процессом про запас. Как правило, большинство приложений не использует все свое рабочее множество, оно устанавливается операционной системой при запуске, причем практически «на глаз», а если приложение требует больше памяти, чем было выделено при запуске, то, рабочее множество автоматически расширяется. Расширение рабочего множества – операция не быстрая, поэтому лучше оставлять его с запасом, что операционная система собственно и делает.
Изучение методик похудения.
Если вы все-таки хотите чтобы ваша программа была «незаметна» в памяти, есть возможность немного подрезать свое рабочее пространство, прибегнув к Win32 API функции SetProcessWorkingSetSize. Первым параметрам данной функции передается хендл процесса, а вторым и третьим соответственно минимальный и максимальный размер рабочего пространства. Ну, вроде бы все ясно, остался только один не решенный вопрос, как же рассчитать необходимый размер рабочего пространства, тут оказалось все просто нужно передать вторым и третьим параметром -1 и Windows сама рассчитает минимальный размер памяти необходимый нашему приложению.
От слов к делу. Худеем вместе.
Объявление API функции в VisualBasic.NET:
1 2 3 4 5 | Public Class NativeMethods <DllImport("kernel32.dll")>_ Public Shared Function SetProcessWorkingSetSize(ByVal handle As IntPtr, ByVal minimumWorkingSetSize As Integer, ByVal maximumWorkingSetSize As Integer) As Boolean End Function End Class |
Вызов функции:
1 2 3 | Private Sub Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load NativeMethods.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1) End Sub |
Компилируем, запускаем, смотрим в диспетчере задач (Ctrl+Shift+Esc) или (Ctrl+Alt+Del), о чудо программа занимает всего 400 килобайт с хвостиком. Но радость наша не долга, память опять начинает упорно расти. Что делать? Не в таймере, же вызывать функцию, это очень не красивое решение. Чтобы обуздать ненасытную программу я предлагаю вот такое решение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Private Sub Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 'Когда приложение будет переходить в состояние простоя 'будем выполнять сборку мусора и освобождение неиспользуемой памяти AddHandler Application.Idle, AddressOf FlushMemory End Sub Private Sub FlushMemory() 'Сборка мусора GC.Collect() GC.WaitForPendingFinalizers() 'Освобождаем неиспользуемую память If System.Environment.OSVersion.Platform = PlatformID.Win32NT Then NativeMethods.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1) End If End Sub |
Компилируем, запускаем, смотрим. Теперь все в порядке.
Оставьте отзыв
Вы должны войти, чтобы оставить отзывы.
