Вопросы по боксу - PullRequest
       24

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

1 голос
/ 07 марта 2009

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

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

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

1) http://en.csharp -online.net / Классы, структуры и объекты - упаковка и распаковка

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

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

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

Ответы [ 4 ]

4 голосов
/ 07 марта 2009

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

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

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

1 голос
/ 07 марта 2009

Пара других вещей для рассмотрения -

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

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

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

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

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

1 голос
/ 07 марта 2009

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

0 голосов
/ 07 марта 2009

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

Типы значений, объявленные как члены экземпляра, будут находиться в памяти до тех пор, пока объект
удаляется GC.

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

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

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

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

<code>
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

...