Pull to refresh

Comments 14

1)Про какую версию net вы пишите? Просто раньше точно было увеличение размера массива в два раза, что собственно снижало производительность из-за нагрузки на память. Сейчас же я вижу +1 к предыдущему размеру,возник вопрос. 2) вы написали, что List<t> будет быстрее ArrayList. Не всегда. Основное преимущество дженерик типов, как вы и написали, уход от упаковки объектов. Но если у нас ссылочные объекты, то их и упаковывать не надо. Вывод: дженерик будет быстрее, только для значимых типов. Для ссылочные типов может быть почти одинаковой, если задать правильную емкость. Пожалуйста, поправьте в статье.

По поводу +1 внимательно почитайте код метода Grow: значение аргумента используется при необходимости для коррекции после попытки удвоения размера.

1) Посмотрите внимательно код Grow. Увеличивается в 2 раза, и проверяется, что новое capacity удовлетворено.

Я видел код, поэтому и возник вопрос о версии платформы, раньше иначе было

1) Актуальный на сегодняшнее время .NET 6.0.9. Как вам уже ответили ранее, размер увеличивается в два раза. В статье написано про это в описании алгоритма работы метода Grow:

если внутренний массив пуст, то ёмкость списка будет равна 4, иначе удвоенной длине массива

2) Я согласен, что наибольший выигрыш будет при использовании значимых типов, в этом и суть. А про разницу для ссылочных типов есть в статье:

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

Значит в net6 переработали код работы со списками. Раньше был иначе. Размер был с ёмкостью по умолчанию 7, потом увеличивая в 2 раза

А не подскажете в какой версии было иначе? Я посмотрел .net 5 и .net framework 4.8 и 4.5.1, везде ёмкость по умолчанию равна 4.

Продолжая обсуждение роста размера: известно, что рост x2 это очень неудачный выбор точки зрения фрагментирования памяти. Разработчики .NET скорее всего в курсе этого, и даже интересно, почему тогда не исправлено?..

В дотнете управляемая память освобождается только сборщиком мусора и никак иначе. А если он оказался запущен — он заодно и дефрагментацию кучи проведёт.


Поэтому фрагментация памяти — вообще не та проблема о которой следует думать в .NET

Это хорошо, если сборщик мусора действительно проведет дефрагментацию, а не ограничится очисткой освобожденных объектов и добавлением занятого ими места в список свободной памяти. А он может решить сделать именно так, поскольку дефрагментация — операция дорогая. А если внутренний массив оказался достаточно большим, то он вообще попадет в кучу больших объектов, дефрагментацию которой сборщик мусора делает только по особой просьбе.
А потому думать о фрагментации в .NET может все-таки оказаться полезным, но перед тем, как думать, желательно все же померить, что там происходит в реале.

PS На всякий случай уточню: информация о работе сборщика мусора взята из книги Кокосы, 2018 года издания. Совет померить — тоже.
метод OrderBy производит устойчивую сортировку, а Sort – нет.

Раз уж вы, как я понял, заглядывали в исходный код, то было бы неплохо указать, какой метод сортировки реально использует Sort. Иногда это знать полезно: например (вспоминаю теорию), с Quick Sort можно, если не повезет, нарваться на O(N2), а Heap Sort хоть и в среднем медленнее, но дает гарантию, что на квадратичную сложность не нарвешься с любыми данными.

Да, вы правы, можно было бы написать про это. Про используемые алгоритмы сортировки есть на MSDN:

This method uses Array.Sort, which applies the introspective sort as follows:

1) If the partition size is less than or equal to 16 elements, it uses an insertion sort algorithm;

2) If the number of partitions exceeds 2 log n, where n is the range of the input array, it uses a Heapsort algorithm;

3) Otherwise, it uses a Quicksort algorithm.

....

This method is an O(n log n) operation, where n is Count.

Про выделение памяти полезно ещё в Diagnostic Tools глянуть на выходе из метода.

static void Main()
{
    var count = 1000000;
    var collection = new ArrayList(count);
    for (var i = 0; i < count; i++)
        collection.Add(i);
}

Выше приведенный код даст помимо ArrayList миллион упакованных Int32.

ArrayList здесь ссылается на Object[], который ссылается на Int32.

Использование List<int> дает другую картину.

static void Main()
{
    var count = 1000000;
    var collection = new List<int>(count);
    for (var i = 0; i < count; i++)
        collection.Add(i);
}

Никаких упакованных Int32. List<Int32> ссылается на Int32[]. Использование памяти значительно сокращено.

Нисколько не критикуя сказанное, обращу внимание на то, что для полноты картины не хватает примера с List<int> без указания начальной ёмкости.

Sign up to leave a comment.