Заставить C#/.NET иметь небольшую площадь?
Я замечаю обычный большой объем памяти. Одно приложение, которое я написал, - это консольное приложение, которое использует <50 линий и просто загружает серию файлов исключительно с помощью WebRequest. Еще одно нетривиальное приложение (mysql, dls, многопоточность, список с 100 элементами). Первый использует 21 МБ (debug, ide), другой использует 39 МБ (debug, ide). У меня также есть другое приложение, опрашивающее мой сайт (также использующее WebRequest) для обновления статуса, которое находится на моем трее и уведомляет меня, используя 26 МБ (выпуск, не проходил через ide).
Почему это так высоко? я знаю, что написал приложение для C++ выше, используя curl, который работал <2mb, а мой самый большой C++ prj - 11mb, который загружает в dll по 100 КБ и в двоичный файл по 200 КБ (используя directx с иконками и звуком win32). Как я могу скомпилировать мой код C#, чтобы он был более дружественным к пространству. Я хотел бы развернуть их на сервере, который может иметь только 128 или 256 МБ оперативной памяти, и некоторые из этих приложений убьют его.
Примечание к сайту: я запустил первое упомянутое приложение (консоль DLer) в режиме релиза (и через ide), и оно подскочило до 32 Мб. Зачем!?! это более запутанно.
4 ответа
Честно говоря, не беспокойтесь о следе управляемого кода, пока вы не сможете измерить случаи, когда его объем памяти создает проблемы. Когда вы запускаете сборку.NET, CLR делает много разных вещей, слишком много, чтобы перечислять их здесь, но смотрите http://weblogs.asp.net/pwilson/archive/2004/02/14/73033.aspx и для многих других ресурсов см. http://geekswithblogs.net/sdorman/archive/2008/09/14/.net-memory-management-ndash-resources.aspx
Взгляните на эту статью, чтобы узнать, как вы можете определить, что ваше приложение действительно использует с точки зрения памяти, потому что диспетчер задач не показывает реальную историю http://www.codinghorror.com/blog/archives/000271.html
Если вы действительно хотите, чтобы ваша сборка отображалась в диспетчере задач с меньшим объемом памяти, чем нужно, чтобы отбросить управляемый код. Один из способов обмана - это скомпилировать ваше приложение, используя что-то вроде Salamander Protector, которое делает ваше приложение исполняемым, а не сборкой.NET.
Небольшие.NET-приложения не могут реально конкурировать с C/C++-приложениями, когда речь идет об объеме памяти по ряду причин.
.NET время выполнения огромно по сравнению с тем, что нужно нативному приложению для запуска. Чтобы запустить приложение.NET, CLR должен быть в памяти. Он должен не только загружать такие компоненты, как JIT-компилятор, GC и т. Д., Он также нуждается в ряде внутренних структур данных. Например, даже самое простое приложение.NET имеет три домена приложений, два для внутреннего использования CLR и одно для самого приложения.
Кроме того, сборки загружаются, когда они передаются. Несмотря на то что методы не объединяются до тех пор, пока они не понадобятся, сама сборка при загрузке использует много адресного пространства. Когда код соединяется в какой-то момент, он снова сохраняется в памяти как собственный код. Таким образом, по существу скомпилированный код присутствует дважды в приложении.NET.
Наконец, система типов в.NET намного сложнее, чем в приложении C/C++. Каждый отдельный объект несет информацию о своем типе. Это позволяет отражать и другие полезные функции, но это имеет свою цену.
Если вы хотите очень малую площадь, то.NET может быть достаточно хорошим, но это, конечно, не самый очевидный выбор, так как вы будете платить за накладные расходы времени выполнения.
Также, пожалуйста, посмотрите этот связанный вопрос. Сокращение использования памяти приложениями.NET?
Я не эксперт по CLR, но я заметил, что CLR распределяет память по блокам и может очень сильно увеличиваться, даже если ваше приложение не использует столько памяти. В некотором роде CLR любит удерживать память, которая ему не нужна, так что ему не нужно вызывать окна для перераспределения.
Проверьте личные байты вашего приложения. Закрытые байты должны быть более разумным показателем памяти, которую вы фактически используете, а не того, сколько удерживает CLR. Кроме того, установка MaxWorkingSet процесса, кажется, волшебным образом перекалибрует статистику в диспетчере задач.
System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
loProcess.MaxWorkingSet = loProcess.MaxWorkingSet;
Код выше выглядит как кандидат на TheDailyWtf. лол
Следует помнить, что сборщик мусора не всегда освобождает память, пока это не понадобится кому-то еще. Таким образом, даже если ваше приложение может заявить, что использует 100 МБ памяти, в действительности оно может использовать 50 МБ, но сборщик мусора еще не имел причины собирать и освобождать все остальное.
Даже базовая инициализация приложения создает много временных файлов, что заставляет CLR выделять блоки памяти для приложения. Пока в системе достаточно памяти, сборщик мусора будет лениво обнаруживать и очищать неиспользуемую память; это оптимизация скорости. Не беспокойтесь, когда вашей системе потребуется больше памяти, сборщик мусора начнет работать и начнет выполнять более глубокое сканирование.
Убедитесь, что вы не вызываете сборщик мусора вручную, чем чаще он вызывается, тем больше объектов помещается в старшие поколения, которые не будут собираться до тех пор, пока в системе не будет мало памяти.