Попытка сократить сборы GC - PullRequest
2 голосов
/ 28 мая 2009

Может кто-нибудь сказать мне, приведет ли приведенный ниже AddB к меньшему распределению CLR, чем AddA? Я изучил разборку, и похоже, что это так, но я хотел бы получить подтверждение от Experts , пожалуйста. Может ли кто-нибудь обменять эту информацию со мной, пожалуйста?

Ура, Чарли.


namespace A
{
    struct Vec2
    {
        public float x;
        public float y;

        public Vec2 AddA(Vec2 other)
        {
            Vec2 v = new Vec2(); // Reference variable
            v.x = x + other.x;
            v.y = y + other.y;
            return v;
        }

        public Vec2 AddB(Vec2 other)
        {
            Vec2 v;              // Value variable
            v.x = x + other.x;
            v.y = y + other.y;
            return v;
        }
    }
}

Ответы [ 5 ]

6 голосов
/ 28 мая 2009

Если Vec2 равен struct в обоих примерах, используя Vec2 v = new Vec2();, вы не создаете ссылку на вашу структуру, вы просто создаете новую структуру в своем стеке. Если вы не используете ключевое слово new, ваша структура тем не менее создается в стеке, и вы можете инициализировать каждое поле отдельно.

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

Если первый метод использует class вместо struct, то он создает объект для сбора GC, в отличие от второго метода. Поскольку v в AddB размещено в стеке, оно не собирается, стек просто извлекается, когда ваш метод завершается.

3 голосов
/ 28 мая 2009

Код в вашем методе AddA просто делает то же, что и:

public Vec2 AddA(Vec2 other) {
   Vec2 v;
   v.x = 0;
   v.y = 0;
   v.x = x + other.x;
   v.y = y + other.y;
   return v;
}

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

Кроме того, изменяемая структура, как правило, плохая идея. Я бы реализовал это так:

struct Vec2 {

    public float X { get; private set; }
    public float Y { get; private set; }

    public Vec2(float x, float y) {
       X = x;
       Y = y;
    }

    public Vec2 Add(Vec2 other) {
       return new Vec2(X + other.X, Y + other.Y);
    }

}
3 голосов
/ 28 мая 2009

Там нет никаких гарантий ни для чего. Значения не обязательно хранятся в куче.

См. Стек - деталь реализации Эрика Липперта и следующая вторая часть .

1 голос
/ 28 мая 2009

Чтобы добавить к другим ответам:

Во-первых, , код можно улучшить, используя соответствующий конструктор и, таким образом, исключая утомительные назначения. Это не является обязательным: должно быть . Кроме того, было бы хорошо реализовать такую ​​структуру как неизменяемый тип, то есть сделать поля readonly так, чтобы шансы на это вообще не были возможны: таким образом, вы бы реализовали семантику чистого значения. 1010 *

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

1 голос
/ 28 мая 2009

Обратите внимание, что AddA и AddB не отличаются по поведению в памяти, оба будут распределены в стеке. имеет значение , так как AddB не вызывает конструктор по умолчанию для типа и, таким образом, оставляет поля Vec2 неинициализированными, тогда как AddA обнуляет их первыми.

Сказав, что я представляю, что прирост производительности при обнулении содержимого, вероятно, не поддается измерению (если JIT-компилятор вообще даже не удаляет его).

...