Использование «чистого» метода против нового объекта - PullRequest
34 голосов
/ 24 июня 2010

В .NET Framework многие классы System.Collection имеют методы Clear.Есть ли явное преимущество в использовании этого по сравнению с заменой ссылки новым объектом?

Спасибо.

Ответы [ 5 ]

41 голосов
/ 24 июня 2010

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

Например, возможно, у вас есть рабочая очередь, гдеВы храните задачи для выполнения.И в одном или нескольких потоках вы вынимаете рабочие элементы из этой очереди (конечно, вы используете блокировку, чтобы обеспечить доступ к очереди не более чем с одним потоком за раз).Если в какой-то момент вы хотите очистить очередь, вы можете использовать Clear, и все потоки все равно будут указывать на один и тот же объект.

Как здесь при использовании Clearвсе элементы будут удалены, и Count будет 0, но Capacity останется неизменным.Обычно неизменность Capacity - это хорошая вещь (для эффективности), но может быть какой-то крайний случай, когда у вас есть тонна элементов, и вы хотите, чтобы эта память была в конечном счете освобождена.

Ссылка MSDN вышетакже упоминает, что Clear является O (n) операцией.Принимая во внимание, что простая замена ссылки будет операцией O (1), а затем, в конце концов, она будет собирать мусор, но, возможно, не сразу.Но замена ссылки также означает, что память, которая составляет емкость, должна быть перераспределена.

6 голосов
/ 24 июня 2010

Брайан верен, но если быть более точным, метод Clear удаляет все элементы из текущего экземпляра коллекции. Создание новой коллекции и присвоение ей ссылки на вашу переменную даст вам совершенно новый экземпляр и может привести к непредвиденным последствиям в зависимости от того, удерживают ли другие люди ссылку на старый экземпляр. Если другой поток имеет ссылку на эту коллекцию, он все равно будет содержать ссылку на старую коллекцию, даже если вы создали новый экземпляр.

3 голосов
/ 24 июня 2010

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

3 голосов
/ 24 июня 2010

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

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

1 голос
/ 14 сентября 2015

Новый объект вызывает проблемы с памятью, если вы работаете с большими данными и часто манипулируете элементом IEnumerable. Посмотрите на мой пример:

class Lol
{
    int i;
    string s;
    public Lol(int ti, string ts)
    {
        i = ti;
        s = ts;
    }
}

class Program
{
    static List<Lol> lol = new List<Lol>();

    static void Main(string[] args)
    {
        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Stopwatch sw = new Stopwatch();
        sw.Start();
        ListCleaner();
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();

        for (int i = 0; i < 10000000; ++i)
            lol.Add(new Lol(i, i.ToString()));

        Console.WriteLine("lol");

        ListCleaner();
    }

    static void ListCleaner()
    {
        //lol = new List<Lol>();
        lol.Clear();
    }
}

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

Кстати "Console.WriteLine (sw.ElapsedMilliseconds);" (Вы можете использовать ElapsedTicks, потому что его значение значительно отличается от другого.) Строка говорит вам, что очистка занимает больше времени, но избавляет вас от проблем с памятью.

Я заметил, что все это происходит в коде отладки (даже в режиме выпуска). Нет проблем с запуском .exe файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...