Почему boolean потребляет больше памяти, чем char? - PullRequest
26 голосов
/ 15 октября 2008

Почему логическое значение использует 4 байта и символ 2 байта в .NET Framework? Логическое значение должно занимать 1 бит или, по крайней мере, быть меньше чем символ.

Ответы [ 9 ]

50 голосов
/ 15 октября 2008

Это вопрос выравнивания памяти. 4-байтовые переменные работают быстрее, чем 2-байтовые. По этой причине вам следует использовать int вместо байта или short для счетчиков и т. П.

Вы должны использовать 2-байтовые переменные только тогда, когда память важнее скорости. И это причина, по которой char (то есть Unicode в .NET) занимает два байта вместо четырех.

16 голосов
/ 12 января 2009

О boolean

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

По крайней мере, в C # bool (или System.Boolean) - это встроенная структура шириной в 1 байт, которая может быть автоматически упакована, поэтому у вас есть объект (для которого нужно представить как минимум два слова памяти, как минимум, т. е. 8/16 байтов в средах 32/64 бит соответственно) с полем (не менее одного байта) плюс одно слово памяти для указания на него, т. е. всего не менее 13/25 байтов.

Это действительно первая запись Google о "C # примитивных типах". http://msdn.microsoft.com/en-us/library/ms228360(VS.80).aspx

Также в цитируемой ссылке (http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx) также указано, что булево значение по стандарту CLI занимает 1 байт.

На самом деле, однако, единственное место, где это видно, это массивы логических значений - n логических значений будет занимать n байтов. В остальных случаях одно логическое значение может занимать 4 байта.

  • Внутри структуры большинство сред выполнения (также в Java) будет выравнивать все поля с 4-байтовой границей для производительности. Monty JVM для встраиваемых устройств более разумен - я думаю, он оптимально меняет порядок полей.
    • В локальном стеке фреймов / операндов для интерпретатора, в большинстве реализаций, для производительности, одна запись стека имеет ширину в одно слово памяти (и, возможно, в .NET она должна быть шириной 64-битной, чтобы поддерживать double и long, что в .NET используется только 1 запись в стеке вместо 2 в Java). JIT-компилятор может вместо этого использовать 1 байт для логических локальных переменных, сохраняя выравнивание других переменных путем переупорядочения полей без влияния на производительность, если дополнительные издержки того стоят.

О char

char - два байта, потому что, когда требуется поддержка интернационализации, использование двухбайтовых символов внутри является самой безопасной ставкой. Это не связано напрямую с выбором поддержки Unicode, но с выбором придерживаться UTF-16 и базовой многоязычной плоскости. В Java и C # вы можете все время предполагать, что один логический символ вписывается в переменную типа char.

8 голосов
/ 15 октября 2008

Это связано с тем, что в 32-разрядной среде ЦП может обрабатывать 32-разрядные значения быстрее, чем 8-разрядные или 16-разрядные значения, так что это компромисс между скоростью и размером. Если вам нужно сэкономить память и у вас есть большое количество булев, просто используйте uint s и сохраните ваши логические значения как биты 4 байта uint s. Символы имеют ширину 2 байта, поскольку в них хранятся 16-разрядные символы Юникода.

3 голосов
/ 12 января 2009

Независимо от незначительной разницы в памяти, использование логических значений true / false да / нет важно для разработчиков (включая вас самих, когда вам придется пересматривать код год спустя), поскольку оно более точно отражает ваши намерения. Сделать ваш код более понятным гораздо важнее, чем сохранить два байта.

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

2 голосов
/ 12 января 2009

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

1 голос
/ 15 октября 2008

Прежде всего вы должны использовать профилировщик, чтобы определить, где у вас проблемы с памятью, ИМХО.

1 голос
/ 15 октября 2008

Память важна, только если у вас большой массив битов, и в этом случае вы можете использовать класс System.Collections.BitArray.

1 голос
/ 15 октября 2008

Я нашел это: «На самом деле логическое значение равно 4 байтам, а не 2. Причина в том, что именно это CLR поддерживает для логического значения. Временной / пространственный компромисс, в общем, того стоит. Вы должны использовать класс битовых векторов (забудьте, где он находится), если вам нужно собрать кучу бит вместе ... "

Это написано Полом Уиком в http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx

0 голосов
/ 15 октября 2008

Это потому, что Windows и .Net использовали Unicode (UTF 16) с момента их создания в качестве внутреннего набора символов. UTF 16 использует 2 байта на символ или пару 2-байтовых слов на символ, но только если требуется, поскольку это кодировка переменной ширины .

"Для символов в базовой многоязычной плоскости (BMP) результирующая кодировка представляет собой одно 16-разрядное слово. Для символов в других плоскостях кодирование приведет к паре 16-разрядных слов"

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...