Что такое интернирование строк в C#?

«Что такое интернирование строк в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Интернирование строк — это механизм CLR, который хранит в памяти (string intern pool) только одну уникальную копию каждого строкового литерала. Это оптимизация для экономии памяти.

Как работает:

  1. Все строковые литералы в коде автоматически интернируются на этапе компиляции/JIT.
  2. При создании строки CLR сначала проверяет пул. Если строка там есть, возвращается ссылка на существующий объект.

Пример, демонстрирующий разницу:

string literal1 = "Hello";
string literal2 = "Hello"; // Тот же литерал
string dynamicStr = new StringBuilder().Append("He").Append("llo").ToString(); // Создана динамически

// Сравнение ссылок (ReferenceEquals)
Console.WriteLine(object.ReferenceEquals(literal1, literal2)); // True: оба ссылаются на один объект в пуле
Console.WriteLine(object.ReferenceEquals(literal1, dynamicStr)); // False: dynamicStr — новый объект в куче

// Принудительное интернирование динамической строки
string internedDynamic = string.Intern(dynamicStr);
Console.WriteLine(object.ReferenceEquals(literal1, internedDynamic)); // True: теперь ссылка на объект из пула

// Проверка на интернированность
Console.WriteLine(string.IsInterned("Hello") != null); // True
Console.WriteLine(string.IsInterned(dynamicStr) != null); // False (до вызова string.Intern)

Практические соображения:

  • Плюс: Экономит память при множественном использовании одинаковых литералов.
  • Минус: Пул живет до выгрузки домена приложения. Динамическое интернирование большого числа уникальных строк может увеличить потребление памяти без возможности сборки мусора.
  • Использовать string.Intern вручную стоит только для часто повторяющихся строк, создаваемых динамически (например, ключей словаря).