Почему 1-символьная строка .NET 32 байта в x64?

#.net #string #memory #.net-4.0

#.net #строка #память #.net-4.0

Вопрос:

Я пытался выяснить накладные расходы на строку в .NET 4 x64. Это то, что у меня есть до сих пор.

  • 16-байтовый заголовок объекта для x64
  • 4 байта для поля StringLength (arrayLength отсутствует в .NET 4)
  • (длина 1) * 2 байта для содержимого строки (UTF-16, завершается нулем)

Таким образом, вы ожидаете, что строка из 1 символа будет 16 4 4 = 24 байта. Она делится на 8, поэтому ей не нужно никаких дополнений.

Но когда я смотрю на размеры в WinDbg, я вижу, что они занимают 32 байта. Когда я !dumpobject их называю, они говорят, что их размер составляет 28 байт, что, как я полагаю, округляется до 32. Что происходит? Происходит ли еще один раунд выравнивания памяти?

Комментарии:

1. Попробуйте сделать строку длиннее… Сколько памяти для 2, 3 и 4 символов?

2. @xanatos: 2 байта дополнительно на символ.

3. Начальный символ может быть выровнен?

4. @leppie Итак, 28 = 1 символ, 30 = 2 символа, 32 = 3 символа и 34 = 4 символа?

5. @xanatos: Прочитайте вопрос еще раз. 1 символ равен 32 🙂

Ответ №1:

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

 32 bit: 14   length * 2 (rounded up to 4 bytes) 
64 bit: 26   length * 2 (rounded up to 8 bytes)
  

Итак, в 64-разрядной среде CLR даже строка длиной 0, по моим подсчетам, занимает 32 байта.

Комментарии:

1. Кажется вероятным, что это 8-байтовое выравнивание по первому символу плюс 8-байтовое заполнение объекта в целом. Я полагаю, что следующий вопрос будет заключаться в том, какие поля будут выровнены таким образом. Я покопался, и это, похоже, не является общим правилом: например, когда вы смешиваете длинные и целые числа в классе, они с удовольствием плотно упаковываются вместе и не выравниваются по 8-байтовым границам. Поиск в Интернете ничего не дал. 🙁

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

Ответ №2:

Округление до границ абзаца (16 байт) для оптимизации заполнения строки кэша на процессорах Intel?

Комментарии:

1. Я не думаю, что это так, потому что я также вижу кучу 40-байтовых строк в WinDbg.

Ответ №3:

Из того, что я понимаю, вы не можете полагаться ни на что на стороне реализации с .NET — только потому, что это x байт на вашем компьютере, это не значит, что это x байт на какой-то другой машине / версии .NET. т. Е. Опасно делать что-либо в коде, зная внутреннюю структуру структуры .NETклассы.

Комментарии:

1. Верно, но этот конкретный вопрос, похоже, вызван простым любопытством.