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

Положите GC на удержание во время раздела кода

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

Есть ли способ обойти это полностью и сказать .NET "выделить все, что вам нужно, не выполнять GC period" или увеличить размер сегментов? Из того, что я нашел, это не более 1 ГБ на многих основных серверах, и это намного меньше, чем то, что мне нужно выделить, но я не хочу, чтобы GC произошел (у меня есть до терабайт свободной оперативной памяти, и есть тысячи всплесков GC во время этого раздела я был бы более чем счастлив обменять их на 10 или даже 100 раз на использование ОЗУ).

Изменить:

Теперь, когда есть щедрость, я думаю, что это проще, если я укажу вариант использования. Я загружаю и разбираю очень большой XML файл (1 ГБ в настоящее время, 12 ГБ в ближайшее время) в объекты в памяти с использованием LINQ to XML. Я не ищу альтернативы этому. Я создаю миллионы мелких объектов из миллионов XElements, и GC пытается собирать нон-стоп, в то время как я был бы очень доволен тем, что оставил всю эту RAM. У меня есть 100 ГБ ОЗУ, и как только он набирает 4 ГБ, GC начинает собирать нон-стоп, который очень дружелюбен к памяти, но недружественный по производительности. Я не забочусь о памяти, но я забочусь о производительности. Я хочу принять противоположный компромисс.

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

var items = XElement.Load("myfile.xml")
.Element("a")
.Elements("b") // There are about 2 to 5 million instances of "b"
.Select(pt => new
{
    aa = pt.Element("aa"),
    ab = pt.Element("ab"),
    ac = pt.Element("ac"),
    ad = pt.Element("ad"),
    ae = pt.Element("ae")
})
.Select(pt => new 
{
    aa = new
    {
        aaa = double.Parse(pt.aa.Attribute("aaa").Value),
        aab = double.Parse(pt.aa.Attribute("aab").Value),
        aac = double.Parse(pt.aa.Attribute("aac").Value),
        aad = double.Parse(pt.aa.Attribute("aad").Value),
        aae = double.Parse(pt.aa.Attribute("aae").Value)
    },
    ab = new
    {
        aba = double.Parse(pt.aa.Attribute("aba").Value),
        abb = double.Parse(pt.aa.Attribute("abb").Value),
        abc = double.Parse(pt.aa.Attribute("abc").Value),
        abd = double.Parse(pt.aa.Attribute("abd").Value),
        abe = double.Parse(pt.aa.Attribute("abe").Value)
    },
    ac = new
    {
        aca = double.Parse(pt.aa.Attribute("aca").Value),
        acb = double.Parse(pt.aa.Attribute("acb").Value),
        acc = double.Parse(pt.aa.Attribute("acc").Value),
        acd = double.Parse(pt.aa.Attribute("acd").Value),
        ace = double.Parse(pt.aa.Attribute("ace").Value),
        acf = double.Parse(pt.aa.Attribute("acf").Value),
        acg = double.Parse(pt.aa.Attribute("acg").Value),
        ach = double.Parse(pt.aa.Attribute("ach").Value)
    },
    ad1 = int.Parse(pt.ad.Attribute("ad1").Value),
    ad2 = int.Parse(pt.ad.Attribute("ad2").Value),
    ae = new double[]
    {
        double.Parse(pt.ae.Attribute("ae1").Value),
        double.Parse(pt.ae.Attribute("ae2").Value),
        double.Parse(pt.ae.Attribute("ae3").Value),
        double.Parse(pt.ae.Attribute("ae4").Value),
        double.Parse(pt.ae.Attribute("ae5").Value),
        double.Parse(pt.ae.Attribute("ae6").Value),
        double.Parse(pt.ae.Attribute("ae7").Value),
        double.Parse(pt.ae.Attribute("ae8").Value),
        double.Parse(pt.ae.Attribute("ae9").Value),
        double.Parse(pt.ae.Attribute("ae10").Value),
        double.Parse(pt.ae.Attribute("ae11").Value),
        double.Parse(pt.ae.Attribute("ae12").Value),
        double.Parse(pt.ae.Attribute("ae13").Value),
        double.Parse(pt.ae.Attribute("ae14").Value),
        double.Parse(pt.ae.Attribute("ae15").Value),
        double.Parse(pt.ae.Attribute("ae16").Value),
        double.Parse(pt.ae.Attribute("ae17").Value),
        double.Parse(pt.ae.Attribute("ae18").Value),
        double.Parse(pt.ae.Attribute("ae19").Value)
    }
})
.ToArray();
4b9b3361

Ответ 1

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

        GC.TryStartNoGCRegion(10000000000); // On Workstation GC this crashed with a much lower number, on server GC this works

Это идет вразрез с моими ожиданиями (это 10 ГБ, но из того, что я мог найти в doc онлайн, мой размер сегмента в моей текущей настройке должен быть от 1 до 4 ГБ, поэтому я ожидал недействительный аргумент).

С этой настройкой у меня есть то, что я хотел (GC находится на удержании, у меня выделено 22 ГБ вместо 7, все временные объекты не GCed, но GC работает один раз (один раз!) по всему пакетному процессу вместо многих раз в секунду (до изменения вид GC в визуальной студии выглядел как прямая линия из всех отдельных точек запуска GC).

Это не очень удобно, так как он не будет масштабироваться (добавление 0 приводит к сбою), но это лучше всего, что я нашел до сих пор.

Если кто-либо не узнает, как увеличить размер сегмента, чтобы я мог продвинуть это дальше или у вас есть лучшая альтернатива полностью остановить GC (а не только определенное поколение, но все это), я приму свой ответ в несколько дней.

Ответ 2

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

var currentLatencySettings = GCSettings.LatencyMode;   
GCSettings.LatencyMode = GCLatencyMode.LowLatency;

//your operations

GCSettings.LatencyMode = currentLatencySettings;

Вы прессуете столько, сколько сможете (по моим сведениям), и вы все равно можете вызвать GC.Collect() вручную.

Посмотрите на статью MSDN здесь

Кроме того, я бы настоятельно предложил подкачки проанализированной коллекции с использованием методов LINQ Skip() и Take(). И, наконец, объединение выходных массивов

Ответ 3

Я не уверен, возможно ли это в вашем случае, однако вы пытались обработать ваш XML файл параллельно. Если вы можете разбить свой XML файл на более мелкие части, вы можете создать несколько процессов из своего кода. Каждый процесс обрабатывает отдельный файл. Затем вы можете комбинировать все результаты. Это, безусловно, увеличит вашу производительность, а также при каждом отдельном процессе вы будете иметь отдельное распределение памяти, что также должно увеличить выделение памяти в определенное время при обработке всех файлов XML.