Строковый тип данных является одним из наиболее важных в любом языке программирования.
Без использования этого типа данных вряд ли можно написать полезную программу.
Однако многие разработчики не знают некоторых нюансов, связанных с этим типом.
Итак, давайте посмотрим на некоторые возможности этого типа в .
NET.
Итак, начнем с представления строк в памяти.
В .
NET строки упорядочиваются в соответствии с правилом BSTR (базовая строка или двоичная строка).
Этот метод представления строковых данных используется в COM (слово «базовый» из языка программирования VisualBasic, в котором оно изначально использовалось).
Как известно в C/C++, PWSZ используется для представления строк, что означает Указатель на строку расширенных символов, завершающуюся нулем .
При таком расположении в памяти в конце строки стоит символ, заканчивающийся нулем, по которому мы можем определить конец строки.
Длина строки в PWSZ ограничена только объемом свободной памяти.
С BSTR дела обстоят немного иначе.
Основные особенности BSTR-представления строки в памяти:
- Длина строки ограничена определенным числом, в отличие от PWSZ, где длина строки ограничена наличием свободной памяти.
- Строка BSTR всегда указывает на первый символ в буфере.
PWSZ может указывать на любой символ в буфере.
- BSTR всегда имеет нулевой символ в конце, как и PWSZ, но в отличие от последнего это допустимый символ и может появляться в любом месте строки.
- Благодаря наличию нулевого символа в конце BSTR совместим с PWSZ, но не наоборот.
NET представлены в памяти согласно правилу BSTR. Буфер содержит четырехбайтовую строку, за которой следуют двухбайтовые строковые символы UTF-16, за которыми следуют два нулевых байта (\u0000).
Использование такой реализации имеет ряд преимуществ: длину строки не нужно пересчитывать; он хранится в заголовке, строка может содержать нулевые символы где угодно, и, что наиболее важно, адрес строки (закрепленный) можно легко передать в неуправляемый код, где ожидается WCHAR*.
Давайте двигаться дальше.
Сколько памяти занимает строковый объект?
Мне попадались статьи, где было написано, что размер строкового объекта равен size = 20 + (длина/2)*4, но эта формула не совсем корректна.Начнем с того, что строка является ссылочным типом, поэтому первые 4 байта содержат SyncBlockIndex, а вторые 4 байта содержат указатель на тип.
Размер строки = 4 + 4 + .
Как уже говорилось выше, в буфере сохраняется длина строки — это поле int, а это значит еще 4 байта.
Размер строки = 4 + 4 + 4 +.
Чтобы быстро передать строку в неуправляемый код (без копирования), в конце каждой строки стоит символ с нулевым завершением, который занимает 2 байта, что означает Размер строки = 4 + 4 + 4 + 2 +.
Остается помнить, что каждый символ в строке находится в кодировке UTF-16, а значит, тоже занимает 2 байта, поэтому Размер линии = 4 + 4 + 4 + 2 + 2 * длина = 14 + 2 * длина Учтем еще один нюанс, и мы на месте.
А именно, менеджер памяти в CLR выделяет память кратно 4 байтам (4, 8, 12, 16, 20, 24,.
), то есть если длина строки в сумме занимает 34 байта, то Будет выделено 36 байт. Нам нужно округлить наше значение до ближайшего большего, кратного четырем, для этого нам понадобится: Размер строки = 4 * ((14 + 2 * длина + 3) / 4) (деление естественно целочисленное) Проблема с версией: В .
NET до версии 4 класс String хранит дополнительное поле m_arrayLength типа int, занимающее 4 байта.
Это поле представляет собой реальную длину буфера, выделенного для строки, включая null — завершающий символ, то есть длину + 1. В .
NET 4.0 это поле удалено из класса, в результате чего объект строкового типа принимает на 4 байта меньше.
Размер пустой строки без поля m_arrayLength (то есть в .
NET 4.0 и выше) = 4 + 4 + 4 + 2 = 14 байт, а с этим полем (то есть ниже .
NET 4.0) = 4. + 4 + 4 + 4 + 2 = 18 байт. Если округлить на 4 байта, то соответственно 16 и 20 байт.
Строковые функции
До сих пор мы рассматривали, как представляются строки и сколько памяти они на самом деле занимают. Теперь поговорим об их особенностях.Основные возможности строк в .
NET:
- Это ссылочные типы.
- Они неизменны.
Как только мы создадим строку, мы больше не сможем ее изменить (справедливым образом).
Каждый вызов метода этого класса возвращает новую строку, а предыдущая строка становится объектом сбора мусора.
- Они переопределяют метод Object.Equals, чтобы он сравнивал не значения ссылок, а значения символов в строках.
Строки являются ссылочными типами
Строки являются настоящими ссылочными типами, то есть они всегда размещаются в куче.Многие люди путают их с типами значений, потому что они ведут себя одинаково, например, они неизменяемы и сравниваются по значению, а не по ссылке, но помните, что это ссылочный тип.
Строки неизменяемы
Строки неизменяемы.Это было сделано не просто так.
Неизменяемость строк имеет множество преимуществ:
- Тип string является потокобезопасным, поскольку ни один поток не может изменить содержимое строки.
- Использование неизменяемых строк снижает нагрузку на память, поскольку нет необходимости хранить два экземпляра одной и той же строки.
В этом случае потребляется меньше памяти и сравнение происходит быстрее, поскольку требуется только сравнение ссылок.
Механизм, реализующий это в .
NET, называется string interning (пул строк), о нем мы поговорим чуть позже.
- Передавая неизменяемый параметр методу, нам не нужно беспокоиться о его изменении (если, конечно, он не был передан как ссылка или out).
Фемеральные — это структуры данных, которые хранят только свою последнюю версию.
Постоянные структуры — это те, которые сохраняют все свои предыдущие версии при изменении.
Последние фактически неизменяемы, поскольку их операции не меняют существующую структуру, а вместо этого возвращают новую структуру, основанную на предыдущей.
Учитывая, что строки неизменяемы, они могли бы быть постоянными, но это не так.
В .
NET строки эфемерны.
Подробнее о том, почему это так, вы можете прочитать в книге Рика Липперта.
связь Для сравнения возьмем строки Java. Они неизменяемы, как и в .
NET, но также и постоянны.
Реализация класса String в Java выглядит следующим образом:
Теги: #строки #структура данных #структура данных #функции #.public final class String
NET #C++
-
Google Принял Себя За Спамера
19 Oct, 24 -
«Дешевле, Чем Роботы, Надежнее, Чем Люди»
19 Oct, 24 -
Новый Чип Данных Для 4G
19 Oct, 24 -
Когда Марлин Встретил Вск
19 Oct, 24 -
Используете Ли Вы P2P-Сети?
19 Oct, 24 -
Быстрые Роботы Жонглируют Телефонами
19 Oct, 24 -
Моргеллоны 2.0
19 Oct, 24