Ответ
Пул строк (String Pool, или Intern Pool) — это механизм оптимизации в CLR (.NET), который хранит в памяти единственный экземпляр каждого уникального строкового литерала для предотвращения избыточных аллокаций.
Как это работает?
- Во время компиляции: Все строковые литералы, найденные в коде сборки, автоматически помещаются в пул.
- Во время выполнения: Создание строки с одинаковым литеральным значением приводит к возврату ссылки на уже существующий объект из пула.
Демонстрация:
string s1 = "Hello";
string s2 = "Hello";
string s3 = new string('H', 5); // "Hello", но создаётся через конструктор
// Сравнение ссылок
Console.WriteLine(ReferenceEquals(s1, s2)); // True: обе ссылаются на один объект в пуле
Console.WriteLine(ReferenceEquals(s1, s3)); // False: s3 — новый объект в куче
// Явное интернирование строки
string s4 = String.Intern(s3); // Принудительно помещаем s3 в пул
Console.WriteLine(ReferenceEquals(s1, s4)); // True: теперь s4 ссылается на объект из пула
// Проверка наличия в пуле
string interned = String.IsInterned("Hello"); // Вернёт "Hello" (ссылка на объект в пуле)
string notInterned = String.IsInterned(Guid.NewGuid().ToString()); // Вернёт null
Ключевые моменты и практические советы:
- Что попадает в пул автоматически? Только строковые литералы из кода.
- Динамические строки (результаты конкатенации, чтения из файла, ввода пользователя) НЕ интернируются автоматически. Для них нужно явно вызывать
String.Intern(). - Пул живёт в куче и не собирается GC до выгрузки домена приложения. Злоупотребление интернированием для уникальных динамических строк (например, GUID) может привести к утечке памяти.
- Когда использовать
String.Intern? Крайне редко. Возможный сценарий — обработка большого количества повторяющихся строковых значений, полученных динамически (например, парсинг XML/JSON с часто повторяющимися именами тегов). В 99% случаев доверяйте компилятору и CLR. - Сравнение строк: Благодаря пулу, сравнение строковых литералов через
==(которое проверяет ссылки) может быть очень быстрым, но для надёжности всегда используйтеString.Equalsс указаниемStringComparison(например,Ordinal).