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

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

11 голосов
/ 04 января 2012

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

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

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

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

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

Неужели я такой?правильно понимаешь или я что-то упустил?

Ответы [ 9 ]

49 голосов
/ 04 января 2012

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

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

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

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

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

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

Язык C # не делает этого;CLR делает это.

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

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

Могу ли я сделать свою собственную?

Нет в C #, нет.

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

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

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

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

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

Пул, конечно, выделяет нового Frob, если в пуле его нет.Если он есть в пуле, он раздает его и удаляет из пула до тех пор, пока он не будет помещен обратно. (Если вы забудете поместить Frob обратно в пул, GC в конечном итоге доберется до него.) Продолжаястратегия объединения: вы заставляете GC в конечном итоге перемещать всех фробов в кучу второго поколения вместо того, чтобы создавать большое давление сбора в куче нулевого поколения.Затем давление сбора исчезает, потому что новые Лягушки не выделяются.Если что-то еще создает давление при сборе, все Лягушки благополучно находятся в куче второго поколения, где их редко посещают.

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

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

В целом, если вы тот человек, который чувствует себя некомфортно, когда в вашем расписании убирается диспетчер памяти, тогда C # не подходит,Вместо этого рассмотрим С.

10 голосов
/ 04 января 2012

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

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

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

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

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

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

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

7 голосов
/ 04 января 2012

Во-первых, к основному посту Erics о Правда о типах значений

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

Так что, на ваш второй вопрос, не пытайтесь "помочь" ГХ.

Я найду сообщение об этом на компьютерной графике и обновлю этот ответ.

4 голосов
/ 04 января 2012

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

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

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

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

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

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

3 голосов
/ 04 января 2012

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

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

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

1 голос
/ 04 января 2012

Пожалуйста, посмотрите этот связанный вопрос относительно стека и кучи.

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

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

С уважением,

0 голосов
/ 26 июня 2016

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

0 голосов
/ 08 октября 2015

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

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

0 голосов
/ 04 января 2012

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

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

...