Является ли установка элемента 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 произойдет позже, когда весь список не будет использоваться по дороге.
Это игнорирует некоторые проблемы, такие как смена кода позже, и оказывается, что элементы используются позже и неожиданно опустошают хаос.
Ответы
Ответ 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