Struct против класса для долгоживущих объектов

Когда вам нужно иметь очень маленькие объекты, скажем, что содержит 2 свойства float, и у вас будут миллионы из них, которые не будут "уничтожены" сразу, являются ли более предпочтительными или классными структурами?

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

Ответы

Ответ 1

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

Некоторые советы:

:: Структура не должна превышать 16 байт или вы теряете преимущества производительности.

:: Сделать структуру неизменной. Это делает использование более понятным.

Пример:

public struct Point3D {

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

   public Point3D(float x, float y, float z) {
      X = x;
      Y = y;
      Z = z;
   }

   public Point3D Invert() {
      return new Point3D(-X, -Y, -Z);
   }

}

Ответ 2

Ответ зависит от того, где будут сохраняться объекты/значения. Если они должны быть сохранены в нетипизированной коллекции, такой как ArrayList, то вы в конечном итоге боксируете их. Бокс создает обертку объекта для структуры, а след - тот же, что и для объекта класса. С другой стороны, если вы используете типизированный массив, такой как T [] или List, то использование structs будет хранить только фактические данные для каждого элемента с размером отпечатка только для всей коллекции, а не для его элементов.

Таким образом, структуры более эффективны для использования в массивах T [].

Ответ 3

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

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

Ответ 4

Строка выглядит правильно для этого приложения.

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

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

Использование класса для миллионов этих типов данных, вероятно, будет дорогостоящим в объеме сдвига разыменования, которое, вероятно, будет иметь место для операций над этим типом.

Ответ 5

Как правило, большие массивы не сглаженных (то есть не разделенных) данных одного и того же типа лучше всего сохраняются в структурах для производительности, поскольку вы уменьшаете количество указаний. (См. Также when-are-structs-the-answer). Точная разница в производительности между классом и структурой зависит от вашего использования. (Например, в операциях вы только получаете доступ к частям структуры? Много ли вы выполняете временное копирование? Если структура мала, ее, вероятно, всегда лучше использовать, но если она будет большой, создание временных копий может замедлить вас. сделайте его неизменным, вам придется всегда копировать все это, чтобы изменить значение.)

Если сомневаетесь, измерьте.

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

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

Ответ 6

Типы значений (struct) хороши для типа, которые не выделяются в куче часто, то есть они в основном содержатся в другом типе ссылки или значения.

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