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

Является ли установка элемента null в .NET List <T> доступным для коллекции Garbage Collection, и это хорошая идея?

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

List<T> items;
 // ... some stuff is done with the list then finally

 for(int i = 0; i < items.Count; i++)
 {
     SomeOperation(items[i]);
     //items[i] never used again at this point
     // say i do this:
     // items[i] = null;

 }

Если я раскомментирую items[i] = null, это приведет к выкручиванию объекта по индексу i и сделает его доступным для коллекции мусора?

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

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

4b9b3361

Ответ 1

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

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

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

Как упоминалось многими другими, использование этой структуры данных сильно указывает на то, что вы не должны использовать List в первую очередь, а скорее Queue или другую сопоставимую структуру данных, поскольку это будет соответствовать вашему использованию гораздо эффективнее.

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

Ответ 2

Да, если в списке появилась последняя ссылка на элемент установки объекта на указанный индекс до значения null, объект, подходящий для GC.

Это не очень хорошая идея:

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

Если вы попытались установить элемент в null, а профилирование показывает измеримое увеличение производительности/масштабируемости/независимо от того, что вы ищете, - подумайте над переписыванием кода, чтобы использовать другую более подходящую конструкцию, которая лучше выражает временный характер списка (возможно, Queue, Stack или просто IEnumrable с ленивой оценкой)

Когда это может быть полезно (обязательно проверьте профиль):

  • Список
  • содержит большие управляемые объекты, такие как Bitmaps или MemoryStream. В этом случае GC имеет хорошие шансы фактически автоматически запускать и очищать объекты (при условии, что во время итерации больше распределений).
  • содержит небольшие управляемые объекты, содержащие большие объекты без управления (например, глобально выделенные дескрипторы памяти) - настройка на нуль + правильная Утилизация + сила GC может потребоваться для запуска ранней очистки (GC не обнаружит необработанное давление памяти)
  • используется в качестве резервного хранилища для некоторой структуры данных, такой как пользовательские Stack, Queue или CircularBuffer как часть вашего собственного элемента настройки библиотеки default(T)/null - это умный способ предотвратить продление срока действия вашей пользовательской структуры данных объектов, которые больше не используются вашим типом.

Обратите внимание, что в случае реализации пользовательских типов данных вы, вероятно, должны сделать это из-за общего контракта типа данных и не из-за профилирования - то есть ожидается, что Stack полностью забывает об объекте после "Поп". Код должен иметь соответствующий комментарий рядом с internalBuffer[i]=null; - то есть "избегать ссылки на ссылку после удаления объекта из стека".

Ответ 3

Как обсуждалось в другом месте, установка на null должна позволить объекту собирать мусор.

Вы скажете в комментарии

Я рассмотрел использование другой структуры данных, такой как очередь, но это не казалось естественным в контексте другого кода, который, как список, делает.

Вы всегда можете инициализировать Queue из списка:

List<T> list = GetList<T>();

Queue<T> queue = new Queue<T>(list); // O(n)

list.Clear(); // to free up memory as per requirement

Ответ 4

CLR Profiler можно использовать для поиска памяти, выделенной для функций, классов и сборок, для оценки производительности.

Некоторые ссылки:

.NET Best Practice No: 1: - Обнаружение функций памяти высокой памяти в коде .NET

Мониторинг деятельности коллекции мусора в .NET с использованием профайлера CLR