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

Как избежать сбора мусора в приложении .NET в реальном времени?

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

Из звука этого, похоже, вы говорите о детерминированной финализации (деструкторы в С++), которая не существует в С#. Самое близкое, что вы найдете на С#, - это одноразовый паттерн. В основном вы реализуете интерфейс 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;
    }
}

Ответ 10

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

Я остался не в ручном вызове методов GC. Но мне приходилось настраивать несколько вещей, которые были расточительными. Я использовал профилировщик RedGate Ant, чтобы оттачивать ненужные порции. Удивительный инструмент!

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

Ответ 11

У вас может быть ограниченное количество экземпляров каждого типа в пуле и повторное использование уже сделанных с экземплярами. Размер пула будет зависеть от количества сообщений, которые вы будете обрабатывать.

Ответ 12

Вместо того, чтобы создавать новый экземпляр объекта каждый раз, когда вы получаете сообщение, почему бы вам не повторно использовать объекты, которые уже были использованы? Таким образом, вы не будете бороться с сборщиком мусора, и ваша память кучи не будет раздроблена. **

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

Скорее всего, вы захотите "ленивой загрузки" вашего пула с помощью экземпляров, чтобы ваш код легко масштабировался. Таким образом, вашему классу пула необходимо будет обнаружить, когда нулевой экземпляр был вытащен и заполнить его перед тем, как передать его. Затем, когда код вызова помещает его обратно в пул, он является реальным экземпляром.

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

http://geekswithblogs.net/robp/archive/2008/08/07/speedy-c-part-2-optimizing-memory-allocations---pooling-and.aspx

Ответ 13

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