Вопросы о боксе

Я знаю, что бокс - популярная концепция, о которой доступно много информации, но у меня есть несколько вопросов, на которые я не могу найти ответов:

1) Если упаковка приводит к преобразованию типа значения (структуры) в объект (ссылочный тип) или ссылочного типа, тогда зачем использовать тип значения, который будет упакован в коробку и приведет к снижению производительности? Я знаю о преимуществах и пригодности в определенных случаях структуры или класса. Говорят (1), что значения (типы значений) имеют тенденцию жить в стеке во временном хранилище, но как долго? Если мне не нужен тип, как я могу гарантировать, что о нем позаботятся и утилизируют в этот момент? Или здесь в игру вступает одноразовый узор? Я предполагаю, что причина использования структуры будет связана с ее преимуществами.

Интересно, что если я использую структуру для хранения двух строк и поля DateTime, структура будет содержать две ссылки (строки) и DateTime вместе. Я, очевидно, предполагаю, что это быстрее, чем разброс значений. Что мне нужно знать об этом дизайне? (2).

1) http://en.csharp-online.net/Classes,_Structs,_and_Objects%E2%80%94Boxing_and_Unboxing

2) http://dotnetperls.com/Content/Struct-Examples.aspx

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

Спасибо за (потенциальное) образование всем плакатистам! Прошу извинить за возможную наивность. Изучение внутреннего устройства позволяет мне потратить некоторое время на понимание IL и т. Д. (Скоро кое-что, чем нужно заняться).


person GurdeepS    schedule 06.03.2009    source источник


Ответы (4)


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

  • Действуйте как примитивные типы.
  • Иметь размер экземпляра менее 16 байт.
  • Неизменны.
  • Семантика значений желательна.

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

person David Pokluda    schedule 06.03.2009
comment
Они взяты из руководящих принципов .NET и, как правило, являются хорошими вопросами, которые стоит задать себе. - person Ben S; 07.03.2009
comment
Я всегда слышу о желании семантики значений - когда это будет желательно? - person GurdeepS; 07.03.2009
comment
msdn.microsoft.com/en-us/library/ aa664472% 28VS.71% 29.aspx Говорит о семантике значений и о том, когда они полезны. - person Ben S; 07.03.2009
comment
Кроме того, если я использую переменную в рамках метода, и это класс, следует ли мне обернуть ее в структуру? - person GurdeepS; 07.03.2009
comment
Если переменная является примитивной, в этом нет смысла, поскольку у них уже есть семантика значений. Если переменная представляет собой объект, обладающий четырьмя вышеуказанными качествами, она может быть хорошим кандидатом для превращения в структуру, а не в объект. - person Ben S; 07.03.2009
comment
На самом деле я имел в виду существующий тип .NET, который является объектом, но может рассматриваться как структура. - person GurdeepS; 07.03.2009
comment
Типы .NET обычно устанавливаются на правильную ссылку или тип значения для их наиболее распространенных применений. Оборачивая один, вы просто добавляете еще один слой и делаете ваш код более запутанным. - person Ben S; 07.03.2009

Типы значений следует использовать из-за их логической выгоды, а не повышения производительности. При этом, поскольку типы значений управляются в стеке, не нужно участвовать в сборке мусора. Если у вас есть тип, который постоянно создается и отбрасывается (например, int, float, double и т. Д.), Вы можете получить хороший импульс, превратив их в структуры. Следует остерегаться того, что вы должны действительно учитывать это только в том случае, если вы также можете сделать структуру неизменной.

person Michael Meadows    schedule 06.03.2009
comment
Что требуется, чтобы структура была неизменной? Правильно ли я подумал, что просто сделаем его менее заметным и сделаем его доступным только для чтения? - person GurdeepS; 07.03.2009
comment
Кроме того, как вообще происходит удаление типов значений в стеке? - person GurdeepS; 07.03.2009
comment
К сожалению, в C # нет семантики для создания неизменяемых типов. Просто нужно убедиться, что его состояние не может быть изменено после создания. - person Michael Meadows; 07.03.2009
comment
Поскольку типы значений создаются в стеке, они не выделяются, поэтому их не нужно собирать. Они просто занимают место в стеке для блока, в котором они находятся. Когда блок извлекается из стека, переменная больше не занимает память. - person Michael Meadows; 07.03.2009

Еще пара вещей, которые следует учитывать -

Во-первых, вы хотите убедиться, что структуры неизменяемы (в целом). Из-за этого рекомендуется не иметь структур, содержащих ссылочные типы. Строки могут быть исключением из этого правила, поскольку они неизменяемы в C #, но с точки зрения общего правила проектирования я бы с осторожностью относился к этому.

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

На это стоит обратить внимание, если производительность является важной частью вашего приложения. Например, в одном из моих приложений изменение одного типа с класса на структуру сократило на 40% длительный (более 5 минут времени выполнения) процесс. Расположение объектов в памяти близко друг к другу, если вы многократно используете их в тяжелых математических вычислениях, может дать огромный выигрыш.

Теперь - в вашем случае наличие 2 строк и DateTime, вероятно, не увидит никаких улучшений от этого. Типы подпрограмм, которые будут работать со строками, вероятно, не будут выполнять тяжелые вычисления (надеюсь), то есть: преобразование полумиллиона точек в пространстве или выполнение большого матричного решения и т. Д.

Наконец, вы заметите, что .net3.5sp1 сделал структуры намного более полезными. До 3.5sp1 (на x86) не было встраивания методов с вызовами структур. Это ограничивало возможный прирост производительности с помощью структур. Обновление вашего фреймворка может сделать старый структурный код намного быстрее (в некоторых случаях).

person Reed Copsey    schedule 07.03.2009
comment
Если я посмотрю, какие типы являются значениями, а какие - ссылочными, тогда структура будет работать с несколькими выбранными типами значений и всей работой со ссылочными типами, происходящей в классах. Значит ссылочные типы (штриховая строка) неизменны? - person GurdeepS; 07.03.2009
comment
В основном, но наоборот - ссылочные типы обычно являются изменяемыми типами, то есть: свойства меняют свои значения (устанавливаются). С другой стороны, структуры были бы неизменными. По сути, после создания структуры вы никогда не захотите, чтобы она изменялась. Если вам нужно новое значение, вы создаете новую структуру. - person Reed Copsey; 09.03.2009

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

Типы значений, объявленные как члены экземпляра, будут в памяти до тех пор, пока объект
не будет удален сборщиком мусора. < br>
Ссылочные типы хранятся в управляемой куче.
Ссылочные типы, созданные в методе, будут удалены сборщиком мусора
, если ни один объект не содержит ссылку на него.

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

Шаблон Dispose используется для ссылочных типов, но не заставляет GC удалять
объект. Обычно он используется для освобождения неуправляемых ресурсов.

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


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope

person Klinger    schedule 06.03.2009