Как избежать сбора мусора в реальном времени .NET-приложения? - PullRequest
11 голосов
/ 17 сентября 2008

Я пишу финансовое приложение на C #, которое получает сообщения из сети, переводит их в другой объект в соответствии с типом сообщения и, наконец, применяет к ним бизнес-логику приложения.

Дело в том, что после применения бизнес-логики я уверен, что мне больше никогда не понадобится этот экземпляр. Вместо того, чтобы ждать, пока сборщик мусора освободит их, я бы хотел явно «удалить» их.

Есть ли лучший способ сделать это в C #, должен ли я использовать пул объектов для повторного использования всегда одного и того же набора экземпляров, или есть лучшая стратегия.

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

Ответы [ 13 ]

21 голосов
/ 17 сентября 2008

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

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

18 голосов
/ 17 сентября 2008

Смотрите здесь: http://msdn.microsoft.com/en-us/library/bb384202.aspx

Вы можете сказать сборщику мусора, что в данный момент делаете что-то критическое, и он постарается быть вам добрым.

11 голосов
/ 17 сентября 2008

Вы попали в себя - используйте пул объектов и повторно используйте эти объекты. Семантика вызовов этих объектов должна быть скрыта за фасадом фабрики. Вам нужно будет увеличивать пул некоторым заранее определенным способом. Возможно, удваивайте размер каждый раз, когда он достигает предела - алгоритм высокой воды или фиксированный процент. Я действительно настоятельно советую вам не вызывать GC.Collect ().

Когда нагрузка на ваш пул становится достаточно низкой, вы можете уменьшить пул, что в конечном итоге приведет к сбору мусора - пусть CLR об этом беспокоится.

7 голосов
/ 17 сентября 2008

Попытка угадать сборщик мусора, как правило, очень плохая идея. В Windows сборщик мусора является поколенческим , и на него можно положиться довольно эффективно. Есть некоторые отмеченные исключения из этого общего правила - наиболее распространенным является то, что единовременное событие, которое, как вы знаете, на самом деле, привело к гибели многих старых объектов, - как только объекты будут переведены в Gen2 (самый длинный из них) они имеют тенденцию торчать.

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

Следует отметить, что сборщик мусора различен на разных платформах .NET - на компактной платформе (которая работает на Xbox 360 и на мобильных платформах) это сборщик мусора без поколений, и поэтому вы должны быть гораздо более внимательно относитесь к тому, какой мусор генерирует ваша программа.

5 голосов
/ 09 февраля 2009

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

Q: Если по времени важно иметь в виду, что вы слушаете какую-то эзотерическую часть оборудования, и вы не можете позволить себе пропустить прерывание?

A: Если это так, то C # - не тот язык, который вы хотите использовать, вам нужен ассемблер, C или C ++ для этого.

Q: Если по времени Критическое, вы имеете в виду, когда в канале много сообщений, и вы не хотите, чтобы сборщик мусора замедлял работу?

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

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

5 голосов
/ 17 сентября 2008

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

Таким образом вы избегаете не только сборки мусора, но и затрат на регулярное выделение.

Наконец, вы уверены, что GC вызывает у вас проблемы? Вероятно, вам следует измерить и доказать это, прежде чем внедрять какие-либо решения, позволяющие экономить время - возможно, вы вызываете излишнюю работу!

3 голосов
/ 18 октября 2008

Насколько интенсивно приложение? Я написал приложение, которое захватывает 3 звуковые карты (Managed DirectX, 44,1 кГц, стерео, 16-бит) в блоках по 8 КБ и передает 2 из 3 потоков на другой компьютер через TCP / IP. Пользовательский интерфейс отображает индикатор уровня звука и (плавную) прокрутку заголовка / исполнителя для каждого из 3 каналов. Это работает на ПК с XP, 1,8 ГГц, 512 МБ и т. Д. Приложение использует около 5% процессорного времени.

Я остался в стороне от ручного вызова методов GC. Но мне пришлось настроить несколько вещей, которые были расточительными. Я использовал AntG-профилировщик RedGate, чтобы оттачивать расточительные порции. Отличный инструмент!

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

3 голосов
/ 17 сентября 2008

Получите хорошее понимание и почувствуйте, как ведет себя сборщик мусора, и вы поймете, почему то, о чем вы здесь думаете, не рекомендуется. если вы действительно не любите CLR тратить время на перестановку объектов в памяти alot .

2 голосов
/ 18 сентября 2008

Судя по всему, вы говорите о детерминированной финализации (деструкторы в C ++), которой нет в C #. Самая близкая вещь, которую вы найдете в C # - это шаблон Disposable. В основном, вы реализуете интерфейс IDisposable .

Основная схема такова:

public class MyClass: IDisposable
{
    private bool _disposed;

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    protected virtual void Dispose( bool disposing )
    {
        if( _disposed )    
            return;

        if( disposing )
        {
            // Dispose managed resources here
        }

        _disposed = true;
    }
}
2 голосов
/ 17 сентября 2008

Если это абсолютно критично ко времени, вам следует использовать детерминированную платформу, такую ​​как C / C ++. Даже вызов GC.Collect () сгенерирует циклы процессора.

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

...