Структуры против классов


Я собираюсь создать 100 000 объектов в коде. Они маленькие, только с 2 или 3 свойства. Я помещу их в общий список, и когда они будут, я зациклю их и проверю значение a и, возможно, обновить значение b.

быстрее / лучше создавать эти объекты как класс или как структуру?

EDIT

a. свойства являются типами значений (кроме строки, Я думаю?)

b. они могут (мы еще не уверены) иметь метод validate

EDIT 2

мне было интересно: объекты в куче и стеке одинаково обработаны сборщиком мусора, или это работает по другому?

11 81

11 ответов:

это быстрее чтобы создать эти объекты как класс или как структуру?

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

структуры потребляют меньше памяти кучи (потому что они меньше и многое другое легко уплотняются, не потому что они "на стеке"). Но они занимают больше времени для копирования, чем эталонная копия. Я не знаю, каковы ваши показатели производительности для использования памяти или скорости; здесь есть компромисс, и вы человек, который знает, что это такое.

это лучше чтобы создать эти объекты как класс или как структуру?

может быть класс, может быть структура. Как правило: Если объект:
1. Маленький
2. Логически неизменяемое значение
3. Их очень много
Тогда я бы подумал о том, чтобы сделать его структурой. В противном случае я бы придерживался ссылочного типа.

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

объекты в куче и стеке обрабатываются одинаково фигня коллекционер?

нет, они не то же самое, потому что объекты в стеке являются корнями коллекции. Сборщику мусора не нужно никогда спрашивать: "эта вещь в стеке жива?"потому что ответ на этот вопрос всегда "Да, это на стек". (Теперь вы не можете полагаться на это сохранить объект жив, потому что стек-это деталь реализации. Дрожание разрешено вводить оптимизации, которые, скажем, зарегистрируйте то, что обычно было бы значением стека, а затем оно никогда не находится в стеке, поэтому GC не знает, что он все еще жив. Зарегистрированный объект может иметь своих потомков, собранных агрессивно, как только регистр, удерживающий его, не будет прочитан снова.)

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

Это понятно?

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

пример:

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i].id = i;
    list[i].is_valid = true;
}

примерно в 2-3 раза быстрее, чем

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i] = new Value(i, true);
}

здесь Value - это struct С двумя полями (id и is_valid).

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

список вернет копию структуры. Обновление это потребует удаление его из списка и добавление снова, создание новой копии с новыми значениями и присвоение ее индексу списка.

поэтому лучше использовать классы.

связанные чтения: почему изменчивые структуры "злые"?

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

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

подробнее здесь:

http://msdn.microsoft.com/en-us/library/aa288471 (VS. 71). aspx

в этом случае, как вы размещаете их в List<>List<> опирается на массив) было бы более эффективно, с точки зрения памяти, использовать структуры.

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

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

Что касается вашего второго редактирования, GC имеет дело только с кучей, но есть намного больше места в куче, чем в стеке, поэтому размещение вещей в стеке не всегда является победой. Кроме того, список структур-типов и a список типов классов будет в куче в любом случае, так что это не имеет значения в данном случае.

Edit:

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

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

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

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

структура, по своей сути, не что иное, как агрегация полей. В .NET структура может "притворяться" объектом, и для каждого типа структуры .NET неявно определяет тип объекта кучи с теми же полями и методами, которые-будучи объектом кучи-будут вести себя как объект. Переменная, которая содержит ссылку на такой объект кучи ("коробочная" структура), будет демонстрировать ссылочную семантику, но та, которая непосредственно содержит структуру, является просто агрегацией переменная.

я думаю, что большая часть путаницы между структурами и классами связана с тем, что структуры имеют два очень разных случая использования, которые должны иметь очень разные рекомендации по дизайну, но рекомендации MS не различают их. Иногда возникает необходимость в чем-то, что ведет себя как объект; в этом случае рекомендации MS довольно разумны, хотя "16-байтовый предел", вероятно, должен быть больше похож на 24-32. Иногда, однако, то, что необходимо-это агрегация переменных. Структура, используемая для этой цели, должна просто состоять из множества открытых полей и, возможно,Equals переопределить, ToString переопределить, и IEquatable(itsType).Equals реализация. Структуры, которые используются в качестве агрегатов полей, не являются объектами и не должны претендовать на это. С точки зрения структуры, значение поля должно быть не больше и не меньше, чем "последнее, что написано в этом поле". Любое дополнительное значение должно быть определено клиентом код.

например, если переменная-объединения структура-элементы Minimum и Maximum, сама структура не должна обещать, что Minimum <= Maximum. Код, который получает такую структуру в качестве параметра, должен вести себя так, как если бы он был передан отдельно Minimum и Maximum значения. Требование, что Minimum быть не больше, чем Maximum следует рассматривать как требование, что a Minimum параметр не должен быть больше, чем отдельно переданный Maximum один.

полезное шаблон для рассмотрения иногда должен иметь ExposedHolder<T> класс определил что-то вроде:

class ExposedHolder<T>
{
  public T Value;
  ExposedHolder() { }
  ExposedHolder(T val) { Value = T; }
}

если у вас есть List<ExposedHolder<someStruct>>, где someStruct является переменной агрегирующей структурой, можно делать такие вещи, как myList[3].Value.someField += 7;, но myList[3].Value другой код даст ему содержимое Value вместо того, чтобы дать ему средство изменить его. Напротив, если один использовал List<someStruct>, надо бы использовать var temp=myList[3]; temp.someField += 7; myList[3] = temp;. Если используется изменяемый тип класса, то содержимое myList[3] to внешний код потребует копирования всех полей в какой-либо другой объект. Если бы использовался неизменяемый тип класса или структура "объектного стиля", необходимо было бы построить новый экземпляр, который был бы похож на myList[3] за исключением someField который был другим, а затем сохранить этот новый экземпляр в списке.

еще одно примечание: Если вы храните большое количество подобных вещей, может быть полезно хранить их в возможно вложенных массивах структур, предпочтительно пытаясь сохранить размер каждого массива между 1K и 64K или около того. Массивы структур являются особыми, поскольку индексирование дает прямую ссылку на структуру внутри, поэтому можно сказать "a[12].x = 5;". Хотя можно определить массив объектов C# не позволяют им поделиться такой синтаксис с массивами.

с точки зрения c++ я согласен, что он будет медленнее изменять свойства структуры по сравнению с классом. Но я думаю, что они будут быстрее читать из-за структуры выделяется в стеке вместо кучи. Чтение данных из кучи требует больше проверок, чем из стека.

использовать классы.

в целом. Почему бы не обновить значение b по мере их создания?

Ну, если вы идете с struct afterall, то избавиться от строки и использовать фиксированный размер char или байтовый буфер.

Это re: производительность.