C #. NET удаление объектов - PullRequest
       52

C #. NET удаление объектов

8 голосов
/ 21 января 2010

Должно быть легко. Допустим, у меня есть следующий код:

void Method()
{
   AnotherMethod(new MyClass());
}

void AnotherMethod(MyClass obj)
{
   Console.WriteLine(obj.ToString());
}

Если я вызываю «Method ()», что происходит с объектом MyClass, который был создан в процессе? После вызова он все еще существует в стеке, хотя его ничто не использует? Или он сразу удаляется?

Нужно ли устанавливать его в нуль, чтобы GC заметил это быстрее?

Ответы [ 7 ]

13 голосов
/ 21 января 2010

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

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

7 голосов
/ 21 января 2010

Если я вызову «Method ()», что произойдет с объектом MyClass, который был создан в процессе?

Создается в куче GC. Затем ссылка на его местоположение в куче помещается в стек. Затем происходит звонок в AnotherMethod. Затем вызывается метод ToString объекта и выводится результат. Затем AnotherMethod возвращается.

По-прежнему ли он существует в стеке после вызова, даже если его ничто не использует?

Ваш вопрос неоднозначен. Под «вызовом» вы подразумеваете вызов метода или AnotherMethod? Это имеет значение, потому что на данный момент, является ли куча памяти кандидатом на сборку мусора, зависит от того, были ли вы скомпилированы с включенными или выключенными оптимизациями. Я собираюсь немного изменить вашу программу, чтобы проиллюстрировать разницу. Предположим, у вас было:

void Method() 
{ 
   AnotherMethod(new MyClass()); 
   Console.WriteLine("Hello world");
} 

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

void Method() 
{ 
   var temp = new MyClass();
   AnotherMethod(temp); 
   Console.WriteLine("Hello world");
} 

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

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

Или он сразу удаляется?

Ничто не собирается сразу; сборщик мусора работает, когда кажется, что он должен работать. Если вам нужен какой-то ресурс, такой как дескриптор файла, который нужно сразу же очистить, когда вы закончите, используйте блок «using». Если нет, то пусть сборщик мусора решит, когда собирать память.

Нужно ли устанавливать его на нуль, чтобы GC заметил это быстрее?

Вам нужно установить что на ноль? Какую переменную вы имели в виду?

Несмотря на это, у вас нет , чтобы сделать что-нибудь, чтобы заставить сборщик мусора работать. Он работает сам по себе, просто отлично, без запроса от вас.

Я думаю, что вы думаете об этой проблеме. Пусть сборщик мусора сделает свое дело и не переживайте по этому поводу. Если у вас есть реальная проблема с памятью, которая не собирается своевременно, то покажите нам некоторый код, который иллюстрирует эту проблему; в противном случае просто расслабьтесь и научитесь любить автоматическое восстановление памяти.

3 голосов
/ 21 января 2010

Есть ли оно в стеке после вызова

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

Нужно ли устанавливать его в нуль, чтобы GC заметил это быстрее?

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

3 голосов
/ 21 января 2010

На самом деле экземпляр будет объявлен в куче, но взгляните на статью Эрика Липпера, Стек - это деталь реализации .

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

2 голосов
/ 21 января 2010

В C # новый MyClass () ограничен, чтобы жить только внутри Method (), пока он активен. По завершении выполнения AnotherMethod () он выходит из области видимости и рутируется. Затем он остается в куче, пока GC не запустит свой цикл сбора и не определит его как блок памяти без ссылок. Таким образом, он все еще «жив» в куче, но недоступен.

1 голос
/ 21 января 2010

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

Механика этого несколько сложна, и когда эти коллекции произойдут, зависит от множества факторов. GC предназначен для создания этих коллекций в самое оптимальное время (которое он может установить), и поэтому, хотя можно заставить его делать коллекцию, это почти всегда плохая идея.

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

ГХ спроектирован так, чтобы быть максимально эффективным, не думая об этом. Честно говоря, единственное, о чем вам действительно нужно помнить, это быть осторожным при выделении действительно больших объектов, которые будут жить долго, и это, как правило, довольно редко в моем опыте.

0 голосов
/ 21 января 2010

Насколько я знаю, объект действителен только в контексте вашего метода. После выполнения метода «Method ()» он добавляется в очередь на удаление.

...