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

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

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

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

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

Спасибо.

- Brian

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

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 ГБ. Нет никакого сообщения об ошибке или выданного исключения. Монитор производительности сообщает, что % процессорного времени в GC приближается к 100%.

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

12
задан brianberns 22 June 2010 в 16:33
поделиться

2 ответа

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

Обновление

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

Система: Windows 7 64bit, 6 ГБ трехканальной оперативной памяти, 8 ядер.

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

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

Теперь сравним это с выделением объектов в моде, которая выделяет их непосредственно в Large Object Heap (которая не страдает теми же проблемами сметания и продвижения):

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));
        }
    }
}

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

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

Обновление 2

В процессе изучения проблемы я играл с рядом опций\конфигураций, которые не дали ощутимой разницы:

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

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

2
ответ дан 2 December 2019 в 21:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: