Как типы String и Char сохраняются в памяти в .NET?

Мне нужно будет сохранить строку кода языка, такую ​​как "en", которая всегда будет содержать 2 символа.

Лучше ли определить тип как "String" или "Char"?

private string languageCode;

против

private char[] languageCode;

Или есть другой, лучший вариант?

Как они хранятся в памяти? сколько байтов или бит будет выделено им при назначении значений?

Ответ 1

Как они хранятся

Оба значения string и char[] хранятся в куче - так что хранение одинаково. Внутри я бы предположил, что string просто является обложкой для char[] с лотами дополнительного кода, чтобы сделать его полезным для вас.

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

Лучший вариант

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

Размер распределения

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

Накладные расходы .NET-массива?

Альтернативы

Основываясь на вашей информации, что есть только 20 кодов языка и производительность, вы можете объявить свое собственное перечисление, чтобы уменьшить размер, необходимый для представления кодов:

enum LanguageCode : byte
{
    en = 0,
}

Это займет 1 байт, а не 4+ для двух char (в массиве), но ограничивает диапазон доступных значений LanguageCode диапазоном byte - который больше, чем большой достаточно для 20 предметов.

Вы можете увидеть размер типов значений с помощью оператора sizeof(): sizeof(LanguageCode). Перечисления - это не что иное, как базовый тип под капотом, они по умолчанию равны int, но, как вы можете видеть в моем примере кода, вы можете изменить это путем "наследования" нового типа.

Ответ 2

Краткий ответ: используйте строку

Длинный ответ:

private string languageCode;

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

Пока

private char[] languageCode;

будет сохранен в виде массива символов, т.е. в куче будет создан объект Array, а затем он будет использоваться для управления вашими символами. Но он по-прежнему имеет атрибут длины, который хранится внутри, поэтому нет заметной экономии памяти по сравнению со строкой. Хотя, предположительно, массив проще, чем String, и может иметь меньше внутренних переменных, тем самым предлагая меньшую печать папок памяти (это нужно проверить).

Но OTOH вы теряете возможность выполнять строковые операции в этом массиве char. Даже операции, такие как сравнение строк, теперь становятся громоздкими. Короче говоря, используйте строку!

Ответ 3

Как они хранятся в памяти? сколько байтов или бит будет выделено им при назначении значений?

Каждый экземпляр в .NET хранится следующим образом: одно IntPtr -размерное поле для идентификатора типа; еще один для блокировки на экземпляре; остаток - данные поля экземпляра, округленные до величины IntPtr. Следовательно, на 32-битной платформе каждый экземпляр занимает 8 байтов + полевые данные.

Это относится как к string, так и к char[]. Оба они также сохраняют длину данных в виде целочисленного значения IntPtr, за которым следуют фактические данные. Таким образом, двухсимвольный string и двухсимвольный char[], на 32-битной платформе, будет занимать 8 + 4 + 4 = 16 байт.

Единственный способ уменьшить это при сохранении ровно двух символов - сохранить фактические символы или структуру, содержащую символы, в поле или массиве. Все они будут потреблять только 4 байта для символов:

// Option 1
class MyClass
{
    char Char1, Char2;
}

// Option 2
class MyClass
{
    CharStruct chars;
}
...
struct CharStruct { public char Char1; public char Char2; }

MyClass закончит использование 8 байтов (на 32-разрядной машине) для каждого экземпляра плюс 4 байта для символов.

// Option 3
class MyClass
{
    CharStruct[] chars;
}

Это будет использовать 8 байтов для служебных данных MyClass плюс 4 байта для ссылки chars плюс 12 байт для служебных данных массива плюс 4 байта на CharStruct в массиве.

Ответ 4

Если вы хотите сохранить ровно 2 символа и сделать это наиболее эффективно, используйте struct:

struct Char2
{
 public char C1, C2;
}

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

Ответ 5

У строк действительно есть накладные расходы на размер одной длины указателя, т.е. 4 байта для 32-битного процесса, 8 байтов для 64-битного процесса. Но опять же, строки предлагают гораздо больше взамен, чем char массивы.

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