Я читал о поколениях и куче больших объектов. Но я все еще не понимаю, в чем важность (или выгода) наличия кучи больших объектов?
Что могло бы пойти не так (с точки зрения производительности или памяти), если бы CLR просто полагалась на поколение 2 (учитывая, что порог Gen0 и Gen1 мал для обработки больших объектов) для хранения больших объектов?
.net
garbage-collection
clr
large-object-heap
Маниш Басантани
источник
источник
Ответы:
Сборка мусора не только избавляется от объектов, на которые нет ссылок, но и сжимает кучу. Это очень важная оптимизация. Это не только делает использование памяти более эффективным (без неиспользуемых дыр), но и делает кэш ЦП намного более эффективным. Кэш - это действительно большое дело для современных процессоров, они на порядок быстрее, чем шина памяти.
Сжатие выполняется простым копированием байтов. Однако это требует времени. Чем больше объект, тем больше вероятность того, что затраты на его копирование перевешивают возможные улучшения использования кэша ЦП.
Поэтому они провели несколько тестов, чтобы определить точку безубыточности. И мы достигли 85 000 байт в качестве точки отсечения, когда копирование больше не улучшает производительность. За специальным исключением для массивов типа double, они считаются «большими», если в массиве более 1000 элементов. Это еще одна оптимизация для 32-битного кода, распределитель кучи больших объектов имеет специальное свойство: он выделяет память по адресам, выровненным по 8, в отличие от обычного распределителя поколений, который выделяет только выровненные по 4. Это выравнивание имеет большое значение для double , чтение или запись неверно выровненного двойника очень дорого. Как ни странно, в скудной информации Microsoft никогда не упоминаются массивы длинных, непонятно, что с этим делать.
Fwiw, многие программисты обеспокоены тем, что куча больших объектов не сжимается. Это всегда срабатывает, когда они пишут программы, которые занимают более половины всего доступного адресного пространства. Затем с помощью такого инструмента, как профилировщик памяти, выяснилось, почему программа провалилась, хотя все еще оставалось много неиспользуемой виртуальной памяти. Такой инструмент показывает дыры в LOH, неиспользуемые участки памяти, где раньше находился большой объект, но собирался сборщик мусора. Такова неизбежная цена LOH, дыра может быть повторно использована только путем выделения для объекта, равного или меньшего по размеру. Настоящая проблема заключается в предположении, что программе должно быть разрешено использовать всю виртуальную память в любое время.
Проблема, которая в противном случае полностью исчезнет, просто запустив код в 64-битной операционной системе. 64-битный процесс имеет 8 терабайт адресного пространства виртуальной памяти, что на 3 порядка больше, чем 32-битный процесс. Вы просто не можете выбежать из дыр.
Короче говоря, LOH делает код более эффективным. За счет использования доступного адресного пространства виртуальной памяти менее эффективно.
ОБНОВЛЕНИЕ. .NET 4.5.1 теперь поддерживает сжатие свойства LOH, GCSettings.LargeObjectHeapCompactionMode . Остерегайтесь последствий, пожалуйста.
источник
Если размер объекта больше некоторого закрепленного значения (85000 байт в .NET 1), CLR помещает его в кучу больших объектов. Это оптимизирует:
нередко уплотняется)источник
Существенное различие кучи малых объектов (SOH) и кучи больших объектов (LOH) заключается в том, что память в SOH сжимается при сборе, а LOH - нет, как показано в этой статье . Уплотнение больших объектов стоит больших затрат. Подобно примерам в статье, скажем, для перемещения байта в памяти требуется 2 цикла, а затем для сжатия объекта размером 8 МБ на компьютере с частотой 2 ГГц требуется 8 мс, что является большими затратами. Учитывая, что большие объекты (в большинстве случаев массивы) довольно распространены на практике, я полагаю, что это причина, по которой Microsoft закрепляет большие объекты в памяти и предлагает LOH.
Кстати, согласно этому сообщению , LOH обычно не создает проблем с фрагментами памяти.
источник
Принцип заключается в том, что маловероятно (и, вполне возможно, плохо спроектировано), что процесс создаст множество короткоживущих больших объектов, поэтому CLR выделяет большие объекты в отдельную кучу, в которой она запускает сборщик мусора по расписанию, отличному от обычного. http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
источник
Я не являюсь экспертом по CLR, но могу представить, что наличие выделенной кучи для больших объектов может предотвратить ненужную очистку сборщика мусора существующих куч поколений. Для выделения большого объекта требуется значительный объем непрерывной свободной памяти. Чтобы обеспечить это из разрозненных «дыр» в кучах поколений, вам потребуются частые уплотнения (которые выполняются только с циклами GC).
источник