Можно ли подавить сбор GC 2-го поколения в .NET? - PullRequest
5 голосов
/ 22 ноября 2011

Моя программа выделяет очень большое количество экземпляров, которые составляют долгоживущую DAWG.Во время создания этой DAWG бывают случаи, когда прогресс замедляется в 100 раз, и это прекрасно согласуется с .NET, выполняя коллекции GC второго поколения.В течение этих периодов «% времени в ГХ» составляет 99,5%, а «общее количество коллекций второго поколения» увеличивается каждые несколько секунд.После нескольких последовательных сборов поколения 2 они прекращают запуск без видимой причины, и программа снова ускоряется.Через несколько минут цикл возобновляется.

Количество созданных мной экземпляров составляет порядка 25 миллионов, и они занимают несколько ГБ ОЗУ, поэтому неудивительно, что коллекции 2-го поколения принимают этодолго.Что удивительно, так это то, что коллекции второго поколения входят в состав «поездов» и постоянно запускаются.

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

(Я попытался установить GCSettings.LatencyMode в GCLatencyMode.Batch, но проблемаосталось. Объем свободной физической памяти на момент начала работы ГХ составляет около 1 ГБ. Это на 64-битной машине.)

Ответы [ 4 ]

4 голосов
/ 08 мая 2015

В .NET 4.5+ вы можете указать свои предпочтения для меньшего количества коллекций Gen 2, используя новые опции GCLatencyMode.

GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;

Больше информации здесь:

http://blogs.msdn.com/b/dotnet/archive/2012/07/20/the-net-framework-4-5-includes-new-garbage-collector-enhancements-for-client-and-server-apps.aspx

Мое приложение не может переносить паузы в течение определенного промежутка времени

Растущее число разработчиков .NET создало коммерческие приложения и услуги, которые обеспечивают результаты в соответствии с определенным бизнесом требования или SLA. Фондовые рынки являются примерами услуг, которые должны доставлять очень своевременные результаты, пока рынки открыты. Как правило, эти приложения выполняют значительную работу в то время, когда они хотят доставить результаты с низкой задержкой. И все же они не могут терпеть заметного паузы из-за коллекции.

Наши клиенты сказали нам, что они развернут больше памяти на своих серверы, если это сделать, удалят длительное время паузы (которые обычно введена полная блокировка ГК). В .NET Framework 4.5 мы предоставил эту опцию, введя режим SustainedLowLatency, который избегает полной блокировки GC. Этот режим также доступен для рабочая станция GC в .NET Framework 4 через обновление 4.0.3.

Пока действует параметр SustainedLowLatency, поколение 0, поколения 1, и фоновые коллекции поколения 2 все еще происходят и обычно не вызывают заметного времени паузы. Блокирующее поколение 2 сбор происходит только в том случае, если машина не хватает памяти или если приложение вызывает GC, вызывая GC.Collect (). Очень важно, чтобы вы развернули приложения, которые используют параметр SustainedLowLatency на компьютерах, которые имеют адекватной памяти, чтобы они удовлетворяли результирующему росту в куче во время действия настройки.

В .NET Framework 4.5 режим SustainedLowLatency доступен для рабочая станция и сервер GC. Чтобы включить его, установите Свойство GCSettings.LatencyMode для GCLatencyMode.SustainedLowLatency. .NET Framework 4 включает режим LowLatency для рабочей станции GC; тем не менее, этот параметр предназначен для использования только в течение коротких периодов времени. время, в то время как режим SustainedLowLatency предназначен для использования в течение многих больше.

Существует также NoGCRegion, который вы можете попробовать.

https://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode%28v=vs.110%29.aspx

Указывает, что сборка мусора приостановлена, пока приложение выполнение критического пути. NoGCRegion - это значение только для чтения; то есть, Вы не можете назначить значение NoGCRegion для GCSettings.LatencyMode имущество. Вы задаете режим задержки без области GC, вызывая TryStartNoGCRegion и завершите его, вызвав Метод EndNoGCRegion.

3 голосов
/ 09 октября 2015

Начиная с .NET 4.6 вы можете «попытаться запретить» сборку мусора в области кода с помощью методов GC.TryStartNoGCRegion и GC.EndNoGCRegion.

try
{
    GC.TryStartNoGCRegion(TOTAL_SIZE, true);

    <No GC region code here>
}   
finally
{
    if (GCSettings.LatencyMode == GCLatencyMode.NoGCRegion) GC.EndNoGCRegion();
}

Для получения дополнительной информации об аргументах и ​​возможныхисключение см. здесь .

Однако, все еще нет гарантии, что GC не будет вызываться.Например, если вы используете какую-то библиотеку в «Нет кода региона GC», и эта библиотека вызывает GC.Collect (), GC.EndNoGCRegion () выдает не только сборку мусора, но и исключение.

Боюсь, вам придется переосмыслить свой подход, поскольку сборка мусора в .NET, похоже, не создана (начиная с .NET 4.6) для обработки миллионов выделенных объектов со сложными отношениями между ними.Библиотека NFX, упомянутая в одном из постов здесь, является опцией, а также использует структуры, упрощающие модель для сокращения отношений, использования индексов в массивах вместо ссылок и т. Д.

1 голос
/ 13 мая 2015

У нас была похожая проблема с кэшированием данных социальной + маршрутизации.Нам пришлось кэшировать сотни миллионов записей, так как сохранение этого процесса было недостаточно быстрым из-за сетевого трафика (даже на локальном хосте).Вместо этого мы создали специальный 100% управляемый менеджер памяти, который распределяет сегменты byte [] и размещает там дополнительное пространство.Объекты из кучи CLR превращаются в «PilePointers {int сегмент, int адрес}» посредством специальной двоичной сериализации, которая на несколько порядков быстрее, чем BinaryFormatter.Так что теперь граф объектов любой сложности и размера может храниться в течение LOMG TIME в управляемой куче, но пауза блокировки GC <10 мс, полная GC составляет около 30-60 мс. </p>

Мы храним 300 000 000 объектов легко на 64-гигабайтном ПК , и самая интересная часть этого заключается в следующем: решение работает НАМНОГО быстрее, чем хранение объектов в неуправляемой куче через Marshal или вне процессачерез redis / memcache.

Смотрите это: Pile: https://www.youtube.com/watch?v=IUBF2Ncvbbs

Кэш: https://www.youtube.com/watch?v=Dz_7hukyejQ

Получить код (Apache 2): https://github.com/aumcode/nfx

0 голосов
/ 22 ноября 2011

Нет.

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

Проще говоря, CLR не позволяет вам жить так опасно.Если вам нужно ручное управление памятью, то вам нужно сделать свои собственные структуры данных из struct s и управлять всем вручную.


Тем не менее, 25 миллионов - это много объектов, но этоне должно быть нескольких гигабайт, если ваши объекты также не являются относительно большими.Можете ли вы использовать массивы структур вместо классов, чтобы избежать лишних ссылок?Есть ли какая-либо информация, которую вы можете удалить?

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