Подтвердить что ты не робот

Почему по умолчанию сохраняются только литеральные строки в основном пуле?

Почему по умолчанию в основном пуле сохраняются только литеральные строки?

Пример из MSDN:

String s1 = "MyTest";
String s2 = new StringBuilder().Append("My").Append("Test").ToString(); 
String s3 = String.Intern(s2); 
Console.WriteLine("s1 == '{0}'", s1);
Console.WriteLine("s2 == '{0}'", s2);
Console.WriteLine("s3 == '{0}'", s3);
Console.WriteLine("Is s2 the same reference as s1?: {0}", (Object)s2==(Object)s1); 
Console.WriteLine("Is s3 the same reference as s1?: {0}", (Object)s3==(Object)s1);

/*
This example produces the following results:
s1 == 'MyTest'
s2 == 'MyTest'
s3 == 'MyTest'
Is s2 the same reference as s1?: False
Is s3 the same reference as s1?: True
*/
4b9b3361

Ответ 1

Короткий ответ: интернирование литеральных строк дешево во время выполнения и сохраняет память. Внутренние нелитеральные строки являются дорогостоящими во время выполнения и, следовательно, сохраняют крошечный объем памяти в обмен на то, чтобы сделать обычные случаи намного медленнее.

Стоимость "оптимизации" интернинга в режиме "runtime" не оплачивается в пользу и, следовательно, на самом деле не является оптимизацией. Стоимость интернирования литеральных строк дешева и, следовательно, платит за это.

Я более подробно отвечаю на ваш вопрос:

http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx

Ответ 2

Разработчики языка решили, что стоимость интернирования каждой промежуточной строковой стоимости не стоит затрат на производительность. Для запуска сборно-сборных строк требуется единая глобальная слабая карта, которая может стать узким местом при большом количестве потоков.

Ответ 3

Внутренние строки почти не принесли бы пользы в большинстве сценариев использования строк, даже если бы у вас был пул инициализации с низкой стоимостью (идеальная интернирующая реализация). Для того, чтобы интернационализация строк предлагала какую-либо выгоду, необходимо, чтобы несколько ссылок на совпадающие одинаковые строки сохранялись в течение разумного "длительного" времени.

Рассмотрим следующие две программы:

  1. Введите 100 000 строк из текстового файла, каждый из которых содержит некоторый произвольный текст, а затем 100 000 пятизначных чисел. Обратите внимание на каждое число, считанное как индекс на основе нуля, в список из 100 000 строк, которые были прочитаны, и выводит соответствующую строку на выход.
  2. Введите 100 000 строк из текстового файла, выводящего каждую строку, содержащую последовательность символов "fnord".

    Для первой программы, в зависимости от содержимого текстового файла, интернационализация строк может генерировать почти 50 000: 1 экономию памяти (если строка содержит 100 000 одинаковых длинных строк текста) или может представлять собой общий отход (если все 100 000 строк различны). В отсутствие интерполяции строк входной файл с 100 000 идентичными строками заставит 100 000 живых экземпляров одной и той же строки существовать одновременно. При интерполяции строк число живых экземпляров может быть уменьшено до двух. Конечно, компилятор не может даже попытаться угадать, может ли входной файл содержать 100 000 одинаковых строк, 100 000 разных строк или что-то промежуточное.

    Для второй программы маловероятно, что даже идеальная реализация интерполяции строк принесет большую пользу. Даже если все 100 000 строк входного файла оказались идентичными, интернирование не могло сэкономить много памяти. Эффект интернирования заключается не в предотвращении создания избыточных экземпляров строк, а в том, чтобы разрешить идентификацию избыточных экземпляров строк и их отбрасывание. Поскольку каждая строка может быть отброшена после того, как она будет исследована и выведена или нет, единственной возможностью, которую может купить интернинг, будет (теоретическая) способность отбрасывать избыточные экземпляры строк (очень) немного раньше, чем это было бы возможно.

    В некоторых случаях могут быть преимущества для кэширования определенных "промежуточных" результатов строк, но это задача, которую лучше всего оставить программисту. Например, у меня есть программа, которая должна конвертировать много байтов в двухзначные шестнадцатеричные строки. Чтобы облегчить это, у меня есть массив из 255 строк, которые содержат строковые эквиваленты значений от 00 до FF. Я знаю, что в среднем каждая строка в этом массиве будет использоваться, как минимум, сотни или тысячи раз, поэтому кеширование этих строк является огромной победой. С другой стороны, строки можно кэшировать только потому, что я знаю, что они представляют. Я знаю, что для любого n 0-255, String.Format("{0:X2}",n) всегда будет давать одно и то же значение, но я не ожидал, что компилятор узнает об этом.