C# TriStartNoGCRegion «Режим NoGCRegion уже выполняется» исключение, когда GC находится в режиме низкой производительности

#c# #.net-core #garbage-collection

Вопрос:

Я пытаюсь создать ногрегион. Прежде чем я это сделаю, я проверяю, находится ли GC уже в регионе NOGC. Мой отладчик говорит, что это еще не так, он все еще выдает, как если бы это было так. введите описание изображения здесь
введите описание изображения здесь А вот окружающий код для контекста:

         var firstTurn = true;
        GCSettings.LatencyMode = GCLatencyMode.LowLatency;
        while (state0.Round < Constants.MAX_ROUNDS amp;amp; state1.Round < Constants.MAX_ROUNDS)
        {
            Log($"GC Mode at begining: {GCSettings.LatencyMode}");
            if (GCSettings.LatencyMode != GCLatencyMode.NoGCRegion) GC.TryStartNoGCRegion(15728640, true);
            var time = firstTurn ? 900 : 90;
            var action0 = mcts0.GetBest(state0, time);
            var action1 = mcts1.GetBest(state1, time);

            state0.Players[0].Action = action0;
            state0.Players[1].Action = action1;

            state1.Players[0].Action = action1;
            state1.Players[1].Action = action0;

            state0 = actionApplyer.ApplyActions(state0);
            state1 = actionApplyer.ApplyActions(state1);

            firstTurn = false;
            Log($"GC Mode at end: {GCSettings.LatencyMode}");

            if (GCSettings.LatencyMode == GCLatencyMode.NoGCRegion) GC.EndNoGCRegion();
        }
 

Что я делаю не так? И почему среда выполнения говорит, что режим NoCGRegion выполняется, когда я проверяю, что это не так раньше.

Комментарии:

1. Вы пробовали войти NoCGRegion один раз, прежде чем войти в цикл во время выполнения работы, связанной с GC? GC.TryStartNoGCRegion не любит, когда его вызывают вложенным или близко друг к другу.

Ответ №1:

Проблема в том, что код вызывает TryStartNoGCRegion несколько раз вложенным способом, против которого рекомендуют документы (примечания) :

Вы не можете вложить вызовы в метод TryStartNoGCRegion, и вы должны вызывать метод EndNoGCRegion только в том случае, если среда выполнения в настоящее время не находится в режиме задержки в регионе GC. Другими словами, вы не должны вызывать TryStartNoGCRegion несколько раз (после первого вызова метода последующие вызовы не будут успешными), и вы не должны ожидать, что вызовы в EndNoGCRegion будут успешными только потому, что первый вызов в TryStartNoGCRegion удался.

Вызов EndNoGCRegion не происходит, потому что GC находится в режиме с низкой задержкой:

если (GCSettings.LatencyMode == GCLatencyMode.NoGCRegion) GC.EndNoGCRegion();

Таким образом, на следующей итерации цикла код снова пытается войти в NoGCRegion и отключается:

если (GCSettings.LatencyMode != GCLatencyMode.NoGCRegion) GC.TriStartNoGCRegion(15728640, верно);

Стоит отметить, что замечания в документах содержат ряд предостережений об этом типе функциональности и о том, что она может вообще не работать, даже если код вызывает ее правильно. Лично я бы попытался найти решение, которое вообще не требует взаимодействия с GC; на ум приходит mempool.