C # - Сборка мусора

Хорошо, я понимаю, что такое стек и куча (значения находятся в стеке, ссылки в куче).

Когда я объявляю новый экземпляр класса, он сохраняется в куче со ссылкой на эту точку в памяти в стеке. Я также знаю, что C # выполняет собственную сборку мусора (т. Е. Определяет, когда созданный экземпляр класса больше не используется, и освобождает память).

У меня 2 вопроса:

  1. Правильно ли я понимаю сборку мусора?
  2. Могу я сделать свое? Если да, то есть ли какая-то реальная польза в том, чтобы делать это самому, или я должен просто оставить это.

Я спрашиваю, потому что у меня есть метод в цикле For. Каждый раз, когда я прохожу цикл, я создаю новый экземпляр своего класса. В своей голове я представляю себе, как все эти классы лежат в куче, ничего не делают, кроме занимают память, и я хочу избавиться от них как можно быстрее, чтобы все было в порядке!

Я правильно понимаю или что-то упустил?


person JMK    schedule 04.01.2012    source источник
comment
Пусть это сделает сборщик мусора. Вот для чего он нужен. Если через профилирование у вас нет метрик, позволяющих сделать вывод о том, что вам нужно вызывать сборщик мусора вручную.   -  person Jim D'Angelo    schedule 04.01.2012
comment
Вы говорите, типы значений в стеке? blogs.msdn. ru / b / ericlippert / archive / 30.09.2010 /   -  person Paul Turner    schedule 04.01.2012
comment
Пусть делает это дело. Если профилирование показывает, что оно того стоит, рассмотрите возможность объединения объектов.   -  person George Duckett    schedule 04.01.2012
comment
Вы действительно не понимаете стек и кучу. Я рекомендую вам прочитать blogs.msdn.com/b/ericlippert/archive/2009/04/27/ и blogs.msdn.com/b/ericlippert/archive/2010/09/30/   -  person Anthony Pegram    schedule 04.01.2012
comment
используется ли новый экземпляр вне области действия итератора?   -  person Tom Bass    schedule 04.01.2012
comment
Раньше я испытывал то же чувство, когда перешел на C # из C ++. Сначала это кажется грязным, но вы научитесь игнорировать его и позволить сборщику мусора делать свое дело.   -  person Erix    schedule 04.01.2012
comment
Programming Hero - Эта ссылка вызвала у меня такую ​​улыбку, что иногда тебе просто нравится ошибаться!   -  person JMK    schedule 05.01.2012
comment
Когда я впервые увидел статью, мой крошечный ум поразил меня.   -  person Paul Turner    schedule 05.01.2012


Ответы (9)


Хорошо, я понимаю, что такое стек и куча (значения живут в стеке, ссылки в куче

Я не думаю, что вы понимаете стек и кучу. Если значения находятся в стеке, то где же находится массив целых чисел? Целые числа - это значения. Вы говорите мне, что массив целых чисел хранит свои целые числа в стеке? Когда вы возвращаете массив целых чисел из метода, скажем, с десятью тысячами целых чисел в нем, вы говорите мне, что эти десять тысяч целых чисел копируются в стек?

Значения живут в стеке, когда они живут в стеке, и живут в куче, когда они живут в куче. Мысль о том, что тип объекта имеет отношение к сроку хранения, - нонсенс. Места хранения, которые недолговечны, помещаются в стек; места хранения, которые являются долгоживущими, помещаются в кучу, независимо от их типа. Долгоживущий int должен находиться в куче, как и долгоживущий экземпляр класса.

Когда я объявляю новый экземпляр класса, он сохраняется в куче со ссылкой на эту точку в памяти в стеке.

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

Я также знаю, что C # выполняет собственную сборку мусора (т. Е. Определяет, когда созданный экземпляр класса больше не используется, и освобождает память).

В языке C # этого не происходит; CLR делает это.

Правильно ли я понимаю сборку мусора?

Кажется, вы верите в ложь о стеке и куче, так что шансы хорошие, нет, это не так.

Могу я сделать свое?

Не в C #, нет.

Я спрашиваю, потому что у меня есть метод в цикле For. Каждый раз, когда я прохожу цикл, я создаю новый экземпляр своего класса. В своей голове я представляю себе, как все эти классы лежат в куче, ничего не делают, кроме занимают память, и я хочу избавиться от них как можно быстрее, чтобы все было в порядке!

Весь смысл сборки мусора - избавить вас от забот о наведении порядка. Вот почему это называется «автоматический сбор мусора». Это прибирает для вас.

Если вас беспокоит, что ваши циклы создают давление сбора, и вы хотите избежать давления сбора по соображениям производительности, я советую вам придерживаться стратегии объединения. Было бы разумно начать с явной стратегии объединения; это:

while(whatever)
{
    Frob f = FrobPool.FetchFromPool();
    f.Blah();
    FrobPool.ReturnToPool(f);
}

вместо того, чтобы пытаться выполнить автоматическое объединение с помощью восстанавливающего финализатора. Я не рекомендую использовать как финализаторы, так и воскрешение объекта в целом, если вы не являетесь экспертом в семантике финализации.

Пул, конечно, выделяет нового Frob, если его нет в пуле. Если он есть в пуле, он выдает его и удаляет из пула, пока он не будет вставлен обратно. (Если вы забудете вернуть Frob обратно в пул, GC в конце концов доберется до него.) Преследуя Стратегия объединения вы заставляете сборщик мусора в конечном итоге перемещать все Frobs в кучу поколения 2 вместо того, чтобы создавать большое давление сбора в куче поколения 0. Затем давление сбора исчезает, потому что новые Frobs не выделяются. Если что-то еще создает давление сбора, все Фробы благополучно находятся в куче 2-го поколения, где их редко посещают.

Это, конечно, полная противоположность описанной вами стратегии; весь смысл стратегии объединения состоит в том, чтобы заставить объекты висеть вечно. Предметы, вечно висящие рядом, - это хорошо, если вы собираетесь их использовать.

Конечно, не вносите такого рода изменения, пока через профилирование не узнаете, что у вас проблемы с производительностью из-за давления сбора! В настольной среде CLR такая проблема возникает редко; он чаще встречается в компактной среде CLR.

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

person Eric Lippert    schedule 04.01.2012
comment
Также я только что понял, что вы действительно написали связанную статью, на которую ссылались другие, спасибо за то, что прояснили это и научили меня чему-то новому =) - person JMK; 05.01.2012

значения живут в стеке, ссылки в куче

Это детали реализации. Нет ничего, что могло бы помешать .NET Framework хранить и то, и другое в стеке.

Я также знаю, что в C # есть собственная сборка мусора.

C # тут ни при чем. Это услуга, предоставляемая CLR. VB.NET, F # и т. Д. Все еще имеют сборку мусора.

CLR удалит объект из памяти, если у него нет сильных корней. Например, когда ваш экземпляр класса выходит за пределы вашего цикла for. Некоторые из них будут валяться, но в конечном итоге они будут собраны либо сборкой мусора, либо завершением программы.

Могу я сделать свое? Если да, то есть ли реальная выгода в том, чтобы делать это самому, или я должен просто оставить это?

Для принудительного создания коллекции можно использовать GC.Collect. Не стоит этого делать, потому что это дорогостоящая операция. Дороже, чем позволить нескольким объектам занимать память немного дольше, чем они абсолютно необходимы. GC невероятно хорош в том, что делает сам по себе. Вы также будете заставлять недолговечные объекты переходить в поколения, которые они обычно не получали бы.

person vcsjones    schedule 04.01.2012
comment
Я думал, что мусор собирается только тогда, когда создаются новые объекты размером до 'x'MB, поэтому он не всегда будет собираться (за исключением конца программы, я думаю). - person George Duckett; 04.01.2012
comment
@GeorgeDuckett Спасибо, я изменю, чтобы прояснить, что я имел в виду. - person vcsjones; 04.01.2012

Прежде всего, к основополагающему сообщению Эрикса о Правде о типах значений

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

Итак, что касается вашего второго вопроса, не пытайтесь «помочь» GC.

Я найду сообщение об этом в CG и обновлю этот ответ.

person Binary Worrier    schedule 04.01.2012

Могу я сделать свое? Если да, то есть ли какая-то реальная польза в том, чтобы делать это самому, или я должен просто оставить это.

Да, можно с GC.Collect , но нельзя. Сборщик мусора оптимизирован для короткоживущих переменных, входящих в метод, и долгоживущих переменных, которые обычно сохраняются на протяжении всего срока службы приложения.

Переменные, которые находятся между ними, не так распространены и не совсем оптимальны для GC.

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

Также из статьи MSDN Написание высокопроизводительных управляемых приложений: учебник

ГХ самонастраивается и настраивается в соответствии с требованиями приложения к памяти. В большинстве случаев программный вызов GC препятствует этой настройке. "Помощь" сборщику мусора путем вызова GC.Collect более чем вероятно не улучшит производительность ваших приложений.

person Conrad Frix    schedule 04.01.2012
comment
Остерегаться! При первом чтении я увидел ... вызов GC.Collect с большей вероятностью улучшит, чем нет ... скорее, чем ... вызов GC.Collect, скорее всего, не улучшится .... Это предложение является хорошим кандидатом для рефакторинга . - person phoog; 04.01.2012
comment
@phoog ну это цитата, так что все, что я действительно могу сделать, это добавить акцента. - person Conrad Frix; 04.01.2012
comment
Я не хотел критиковать вас, просто чтобы предупредить других о возможном неправильном прочтении. - person phoog; 04.01.2012
comment
@phoog не волнуйтесь, я понял, что вы имеете в виду;) - person Conrad Frix; 04.01.2012

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

Невозможно заставить сборщик мусора собирать только определенный экземпляр. Вы можете попросить его выполнить обычную операцию «собрать все возможное» GC.Collect(), но этого делать не следует. сборщик мусора эффективен и действенен, если вы просто предоставите его собственным устройствам.

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

person Paul Turner    schedule 04.01.2012

См. Этот связанный вопрос относительно стека и кучи. .

В вашем конкретном сценарии, согласованном, если вы создаете новые объекты в цикле for, тогда у вас будет неоптимальная производительность. Сохраняются ли объекты (или используются иным образом) в цикле, или они отбрасываются? Если последнее, можете ли вы оптимизировать это, добавив один объект вне цикла и повторно используя его?

Что касается того, можете ли вы реализовать свой собственный сборщик мусора, в C # нет явного ключевого слова delete, вы должны оставить его для CLR. Однако вы можете дать ему подсказки, например, когда собирать или что игнорировать во время сбора, однако я бы оставил это, если только это не абсолютно необходимо.

С наилучшими пожеланиями,

person Dr. Andrew Burnett-Thompson    schedule 04.01.2012

Прочтите следующую статью Microsoft, чтобы получить более подробные сведения о сборке мусора на C #. Я уверен, что это поможет любому, кому нужна информация по этому поводу.

Управление памятью и сборка мусора в .NET Framework

person Roshana Pitigala    schedule 08.10.2015

Если вас интересует производительность некоторых областей вашего кода при написании C #, вы можете написать небезопасный код. У вас будет плюс в производительности, а также в вашем фиксированном блоке сборщик мусора скорее всего не сработает.

person meJustAndrew    schedule 26.06.2016

Сборка мусора - это в основном отслеживание ссылок. Я не могу придумать какой-либо веской причины, по которой вы хотели бы это изменить. У вас есть какая-то проблема, когда вы обнаруживаете, что память не освобождается? Или, может быть, вы ищете шаблон удаления

Изменить: заменен «подсчет ссылок» на «отслеживание ссылок», чтобы не путать с счетчиком увеличения / уменьшения в ссылке на объект / разыменовании (например, из Python). Я думал, что довольно часто называть создание графа объектов «Подсчетом», как в этом ответе: Почему в C # нет подсчета ссылок и сбора мусора? Но я не буду брать на себя руку Эрика Липперта :)

person Tormod    schedule 04.01.2012
comment
Сборка мусора - это не подсчет ссылок; это метка поколений. - person Eric Lippert; 04.01.2012
comment
Отредактировано. Спасибо, сэр. Мне уже нравится ваш блог, но я вижу, что мне нужно проводить там больше времени. - person Tormod; 05.01.2012