Подтвердить что ты не робот

Явное освобождение памяти в С#

Я создал приложение С#, которое использует до 150 мб памяти (частные байты), в основном из-за большого словаря:

Dictionary<string, int> Txns = new Dictionary<string, int>();

Мне было интересно, как освободить эту память. Я пробовал это:

Txns = null;
GC.Collect();

Но, похоже, это не так много в моих личных байтах - они падают с 155 до 145 мб. Любые подсказки?

Спасибо

-edit -

Хорошо, мне больше повезло с этим кодом (он получает личные байты до 50 МБ), но почему?

Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();

-edit -

Хорошо для всех, кто говорит "не использовать GC.collect", достаточно справедливо (я не буду обсуждать это, кроме как сказать, что вы можете увидеть мой фон C), но на самом деле он не отвечает мой вопрос: Почему сборщик мусора освобождает память только в том случае, если я сначала очистил список транзакций? Разве это не освобождает память, так как словарь разыменован?

4b9b3361

Ответ 1

Частные байты отражают использование памяти процесса. Когда объекты собираются, соответствующий сегмент памяти может быть освобожден или недоступен для ОС. CLR управляет памятью на уровне ОС, и поскольку выделение и освобождение памяти не является бесплатным, нет никаких оснований бесплатно освобождать каждую часть памяти, так как вероятность того, что приложение, вероятно, потребует больше памяти позже.

Ответ 2

если u вызывает GC.Collect(), он начинает выполнять свое задание, но он немедленно возвращается, он не блокируется, поэтому вы не видите его влияния, если вы просто вызываете GC.WaitForPendingFinalizers() после этого, это заблокирует ваше приложение пока GC.Collect() не закончит свою работу

Ответ 3

Скорее всего, у вас есть скрытая ссылка на словарь где-то в другом месте. Таким образом, словарь не собирается, но если вы Clear() его, содержимое будет собрано.

Как уже отмечалось, принудительное включение GC не рекомендуется. Это может привести к тому, что память будет переведена в более высокие "поколения", которые не часто собираются, тем самым теряя больше памяти, чем в конечном итоге.

Ответ 4

Не уверен в памяти, если Dictionary имеет Dispose() или нет, но он должен иметь Clear(). Вызовите любой из них, прежде чем устанавливать какие-либо ссылки на null.

Тогда просто позвольте сборщику мусора выполнить свою работу. Практически никогда не рекомендуется явно вызывать GC.Collect() самостоятельно, и это может даже не делать то, что вы хотите/нуждаетесь/ожидаете, и в конечном итоге стоите вам производительности. Анализ статического кода (= FxCop) не предупреждает вас о Правиле надежности CA2001 об этом для ничего, вы знаете? Просто не делайте этого, если вы действительно не знаете, что делаете. И даже тогда этого не делать.; -)

Вы уверены, что словарь настолько огромен? Разве это не 10 Мб памяти, а остальное в другом случае используется вашим приложением? Вопрос, который может вам помочь: вы использовали профилировщик еще, чтобы увидеть, где действительно потребляется память??

Ответ 5

Edit:

Чтобы быть справедливым, установка ссылки на null не освобождает память, она присваивает ей контейнер другому адресу, в этом случае null. Согласно MSDN, вызывая Clear(), делает следующее: "Свойство Count установлено в 0, а ссылки на другие объекты из элементов из коллекции также выпущены. Емкость остается неизменной".

...

Вы никогда не должны звонить сборщику мусора. Вы используете управляемые объекты без собственных ресурсов, доверяйте сборщику мусора для очистки после вас.

Помимо размера вашего словаря, вам не нужно беспокоиться о памяти, память не является вашей проблемой, проблема с сборщиками мусора.

Вызов Clear() приведет к удалению ссылок на любой содержащийся объект внутри, но емкость остается неизменной.

С технической записью сбор памяти дорог и требует значительных затрат времени. Причина состоит не только в том, что GC обрабатывает кучу памяти и очищает вашу кучу, но и отчасти дефрагментирует кучу. Он пытается переместить память в смежные блоки, чтобы ускорить выделение, когда какая-то часть кода делает большой запрос.

p.s. Насколько велик ваш словарь, что вы используете 155 МБ памяти?

Ответ 6

Вам нужна память? Память доступна, она просто не восстанавливается. Вы не должны очищать словарь, удерживайте слабую ссылку, чтобы позволить выполнению своей работы.

Если вы хотите глубоко понять, что происходит, ознакомьтесь с .NET Memory Profiler. Это даст вам представление о том, что происходит с вашим объектом, каково его поколение, какая память используется и что дальше и что происходит.:)

Ответ 7

Хорошо, у меня есть теория здесь... Словарь представляет собой набор ключей KeyValuePair, который снова является ссылочным типом.

Ваш словарь содержит эти ключи. Когда вы говорите:

Txns = null

Он освобождает ссылку "Txns" из коллекции KeyValuePair. Но все же фактическая память 150 Мб ссылается на эти KeyValuePair, и они находятся в области видимости, поэтому не готовы к сбору мусора.

Но когда вы используете следующее:

Txns.Clear();
Txns = null;
GC.Collect();

Здесь ясный метод также освобождает 150 Мб данных от соответствующих ссылок на объекты KeyValuePair. Таким образом, эти объекты были готовы к сбору мусора.

Его просто дикая догадка, которую я здесь делаю. Комментарии приветствуются:)

Ответ 8

Windows имеет два события доступности памяти. Я ожидал, что CLR ответит на это. Если доступно много памяти, умная вещь - НЕ запускать сборщик мусора. Поэтому, чтобы убедиться, что вы действительно наблюдаете плохое поведение CLR, повторите этот тест с помощью другого фиктивного приложения, используя большую кучу памяти.

Ответ 9

Обычно это не хорошая идея, пытающаяся заставить GC. Вам действительно нужен весь словарь в памяти?