`Yield return` в C # создает для меня много мусора. Можно ли помочь? - PullRequest
6 голосов
/ 30 апреля 2011

Я разрабатываю игру для Xbox 360 с XNA.Я бы действительно хотел бы использовать конструкцию C # yield return в нескольких местах, но, похоже, она создает много мусора.Посмотрите на этот код:

class ComponentPool<T> where T : DrawableGameComponent
    {
    List<T> preallocatedComponents;

    public IEnumerable<T> Components
        {
        get
            {
            foreach (T component in this.preallocatedComponents)
                {
                // Enabled often changes during iteration over Components
                // for example, it's not uncommon for bullet components to get
                // disabled during collision testing
                // sorry I didn't make that clear originally
                if (component.Enabled)
                    {
                    yield return component;
                    }
                }
            }
        }
    ...

Я использую эти пулы компонентов везде - для пуль, врагов, взрывов;что-нибудь многочисленное и преходящее.Мне часто нужно перебирать их содержимое, и меня всегда интересуют только активные компоненты (т. Е. Enabled == true), поэтому поведение свойства Components.

В настоящее время явидя до 800K в секунду дополнительного мусора при использовании этой техники.Это можно избежать?Есть ли другой способ использовать yield return?

Редактировать: я нашел этот вопрос о более широкой проблеме, как перебирать пул ресурсов без создания мусора.Многие комментаторы были пренебрежительными, по-видимому, не понимая ограничений Compact Framework, но этот комментатор был более отзывчив и предложил создать пул итераторов.Это решение, которое я собираюсь использовать.

Ответы [ 2 ]

3 голосов
/ 30 апреля 2011

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

Если ничего другого, то выражение preallocatedComponents.Where(r => r.Enabled) - это чертовски много кода, на который нужно обратить внимание, чтобы сделать то же самое, что и доходность.

class ComponentPool<T> where T : DrawableGameComponent
    {
    List<T> preallocatedComponents;
    IEnumerable<T> enabledComponentsFilter;

    public ComponentPool()
    {
       enabledComponentsFilter = this.preallocatedComponents.Where(r => r.Enabled);
    }

    public IEnumerable<T> Components
        {
        get { return enabledComponentsFilter; }
        }
    ...
2 голосов
/ 30 апреля 2011

Реализация итераторов компилятором действительно использует объекты класса, и использование (с foreach, например) итератора, реализованного с yield return, действительно приведет к выделению памяти.В схеме вещей это редко является проблемой, потому что либо выполняется значительная работа во время итерации, либо выделяется значительно больше памяти для выполнения других задач во время итерации.

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

Если ваше приложение соответствует этому профилю (и только если), то первое правило, которому вы должны следовать:

  • избегайте итераторов во внутренних циклах, когда доступна более простая концепция итерации

Например, если у вас есть массив или список, подобный структуре данных, вы уже выставляете свойство индексатора и свойство count, чтобы клиенты могли простоиспользуйте цикл for вместо использования foreach с вашим итератором.Это «легкие деньги» для уменьшения GC, и это не делает ваш код уродливым или раздутым, просто немного менее элегантным.

Второй принцип, которому вы должны следовать:

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