Лучший способ распоряжаться списком - PullRequest
29 голосов
/ 06 июля 2011

У меня есть объект List.Как я могу распоряжаться списком?

Например,

List<User> usersCollection =new List<User>();

User user1 = new User();
User user2 = new User()

userCollection.Add(user1);
userCollection.Add(user2);

Если я установлю userCollection = null;, что произойдет?

foreach(User user in userCollection)
{
    user = null;
}

Какой из них лучше?

Ответы [ 17 ]

0 голосов
/ 04 сентября 2013

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

В этих (редких) сценариях я использовал следующий класс:

public class DisposableList<T> : List<T>, IDisposable
{
    public void Dispose()
    {
    }
}

Затем вы можете использовать его как обычный список, например,

var myList = new DisposableList<MyObject>();

Затем вызовите метод Dispose, когда закончите:

myList.Dispose();

Или, альтернативно, объявить это в операторе using:

using (var myList = new DisposableList<MyObject>())
{
    ...
}

Это приводит к тому, что сборщик мусора выполняет сбор сразу после того, как список DisposableList выходит за пределы области действия или удаляется.

0 голосов
/ 30 ноября 2018

Если ваш элемент в списке неуправляемый объект, то вы можете вызывать Dispose () для каждого объекта, повторяя его.

foreach(User user in userCollection)
{
user.Dispose();
}

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

0 голосов
/ 30 марта 2018

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

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

User.BigData = null;

Затем вы можете сохранить список пользователей и позволить сборщику мусора очистить свойства, которые занимают всю вашу память.

0 голосов
/ 27 апреля 2017

Я вижу много ответов, вызывающих удаление объекта в цикле foreach над коллекцией. Так как Dispose просто отмечает объект, который будет удален при следующем запуске сборщика мусора, он будет работать нормально. Тем не менее, теоретически удаление элемента может изменить коллекцию и нарушить foreach, поэтому было бы более надежно сначала собрать эти одноразовые объекты, очистить исходный список и вызвать удаление в цикле for или while, начиная с конца и удаляя объект в каждой итерации, например вызов следующего метода:

    public static void DisposeItemsInList<T>(this IList<T> list) where T : IDisposable
    {
        DeleteItemsInList(list, item => item.Dispose());
    }

    public static void DeleteItemsInList<T>(this ICollection<T> list, Action<T> delete)
    {
        if (list is IList && !((IList)list).IsFixedSize)
        {
            while (list.Count > 0)
            {
                T last = list.Last();
                list.Remove(last);
                delete?.Invoke(last);
            }
        }
        else
        {
            for (int i = 0; i < list.Count; i++)
            {
                delete?.Invoke(list.ElementAt(i));
            }
        }
    }

Я на самом деле использую DeleteItemsInList для других целей, например удалить файлы: DeleteItemsInList (File.Delete))

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

0 голосов
/ 06 июля 2011

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

Сборка мусора: msdn.microsoft.com / ru-ru / library / 0xy59wtx.aspx

0 голосов
/ 06 июля 2011

Как уже упоминалось, отпуск в GC, это лучший вариант, и не заставляйте GC.Установка переменной в нуль пометит переменную для GC.

, если вам нужно больше информации: Наилучшая практика принудительного сбора мусора в C #

0 голосов
/ 06 июля 2011

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

.

void Function()
{
    ... some code here ....

    {   // inside this bracket the usersCollection is alive
        // at the end of the bracet the garbage collector can take care of it

        List<User> usersCollection =new List<User>();

        User user1 = new User();
        User user2 = new User()

        userCollection.Add(user1);
        userCollection.Add(user2);

        foreach(User user in userCollection)
        {

        }
    }

    ... other code here ....
}
...