Подтвердить что ты не робот

Сборщик мусора .NET и виртуальная память x64

Запуск приложения .NET на Windows Server 2008 x64 с 16 ГБ ОЗУ. Это приложение должно извлекать и анализировать очень большой объем данных (около 64 ГБ) и сохранять их все в памяти за один раз.

Что я ожидаю увидеть: размер процесса расширяется с 16 до 64 ГБ. Windows использует виртуальную память для дополнительной записи данных на диск с диска. Это классический вариант использования виртуальной памяти.

Что я на самом деле вижу: размер процесса ограничен объемом физической памяти (16 ГБ). Приложение тратит 99,8% своего времени на сборщик мусора.

Почему наше приложение не использует виртуальную память? Это проблема в конфигурации сборщика мусора .NET или в самом диспетчере виртуальной памяти Windows x64? Что я могу сделать, чтобы заставить наше приложение использовать виртуальную память, а не ограничиваться физической памятью?

Спасибо.

- Брайан

Обновление: я написал очень маленькую программу, которая демонстрирует то же поведение:

using System;

namespace GCTest
{
    class Program
    {
        static void Main()
        {
            byte[][] arrays = new byte[100000000][];
            for (int i = 0; i < arrays.Length; ++i)
            {
                arrays[i] = new byte[320];
                if (i % 100000 == 0)
                {
                    Console.WriteLine("{0} arrays allocated", i);
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }
}

Если вы хотите попробовать, обязательно создайте для x64. Возможно, вам придется немного изменить константы, чтобы подчеркнуть вашу систему. Поведение, которое я вижу, заключается в том, что процесс болит, когда он приближается к размеру 16 ГБ. Не появляется сообщение об ошибке или исключение. Мониторинг производительности сообщает, что% времени процессора в ГК приближается к 100%.

Разве это неприемлемо? Где виртуальная память?

4b9b3361

Ответ 1

Вы проверили, настроен ли ваш файл подкачки таким образом, чтобы он мог расширяться до этого размера?

Обновление

Я немного поиграл с вашим примером, и вот что я вижу.

Система: Windows 7 64 бит, 6 ГБ трехканальной ОЗУ, 8 ядер.

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

  • Я вижу, что большое количество данных продвигается из поколения в поколение в GC, а также большое количество сборок GC/коллекций и огромное количество ошибок страницы в результате, когда достигнуты физические ограничения памяти, Я могу только предположить, что когда физическая память исчерпана\очень высокая, это приводит к тому, что генерация подметает и продвигает, тем самым вызывая большое количество выгружаемой памяти, которая приводит к смерти, когда затронутая память выгружается и другая память вытесняется. Все это заканчивается сырым беспорядком. Это кажется неизбежным при распределении большого количества долгоживущих объектов, которые попадают в кучу мелких объектов.

Теперь сравните это с распределением объектов по модулю, выделив их непосредственно в кучу больших объектов (которая не подвержена таким же колебаниям и вопросам продвижения):

private static void Main()
{
    const int MaxNodeCount = 100000000;
    const int LargeObjectSize = (85 * 1000);

    LinkedList<byte[]> list = new LinkedList<byte[]>();

    for (long i = 0; i < MaxNodeCount; ++i)
    {
        list.AddLast(new byte[LargeObjectSize]);

        if (i % 100000 == 0)
        {
            Console.WriteLine("{0:N0} 'approx' extra bytes allocated.",
               ((i + 1) * LargeObjectSize));
        }
    }
}

Это работает как ожидалось, то есть виртуальная память используется, а затем исчерпана - 54 ГБ в моей конфигурации\конфигурации.

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

Обновление 2

Во время исследования проблемы я играл с несколькими опциями \configurations, которые не делали заметной разницы:

  • Принудительный режим GC Server.
  • Настройка GC с низкой задержкой.
  • Различные комбинации принудительного GC, чтобы попытаться амортизировать GC.
  • Рабочие наборы Min\Max.

Ответ 2

Похоже, вы не держите ссылку на большие данные. Сборщик мусора не будет собирать объекты, на которые ссылаются.