Неизменность строки

Работает ли неизменяемость строк по выражению или по строкам внутри выражения?

Например, я понимаю, что следующий код выделит две строки в куче.

string s = "hello ";
s += "world!";

"Привет" останется в куче, пока мусор не будет собран; и теперь ссылки "привет, мир!" в кучу. Однако сколько строк выделяет следующая строка в куче...1 или 2? Кроме того, есть ли инструмент / способ для проверки результатов?

string s = "goodbye " + "cruel world!";

9 ответов

Решение

Компилятор имеет специальную обработку для конкатенации строк, поэтому вторым примером является только одна строка. И "интернирование" означает, что даже если вы запустите эту строку 20000 раз, все равно останется только 1 строка.

Повторное тестирование результатов... самый простой способ (в этом случае), вероятно, смотреть в отражателе:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] string s)
    L_0000: ldstr "goodbye cruel world!"
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: call void [mscorlib]System.Console::WriteLine(string)
    L_000c: ret 
}

Как вы видете (ldstr), компилятор уже сделал это для вас.

Буквальные строки интернированы, это означает, что "hello " находится не в куче, а в сегменте данных [см. комментарий] программы (и, следовательно, не подходит для сбора мусора), то же самое относится и к "world", что касается "hello world" это может быть также интернировано, если компилятор достаточно умен.

"goodbye cruel world" будет интернирован, поскольку конкатенация строковых литералов обрабатывается компилятором.


Изменить: я не уверен насчет заявления сегмента данных, пожалуйста, смотрите этот вопрос для получения дополнительной информации.

Конечно, не преждевременно оптимизируйте, но не сбрасывайте со счетов то, насколько плохо могут быть конкатенации строк. Это не создание объекта, а работа GC, которую он вызывает.

В блоге Тесс Фернандес (инженер по эскалации ASP.NET) есть лаборатория, в которой показан (довольно экстремальный, само собой разумеющийся) пример того, как объединение строк может поставить сервер на колени.

Если это не просто одна строка, объединение двух строк может быть выполнено путем преобразования первой строки в StringBuffer, выполнения объединения и возврата строки результата.

Создание StringBuffer самостоятельно может показаться излишним, но в любом случае это произойдет.

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

string s = "goodbye " + "cruel world!";

В java выделил бы одну строку. Java играет довольно милые трюки, и их будет сложно перехитрить - просто никогда не оптимизируйте, пока вам это не нужно!

В настоящее время, однако, насколько я знаю, используя это:

String s="";
for(int i=0;i<1000;i++)
    s+=" ";

создать строку из 1000 пробелов все еще имеет тенденцию быть крайне неэффективным

Присоединение в цикле довольно плохо, но в остальном это, вероятно, так же эффективно, как StringBuilder.

Если вы просто собираетесь объединить одну или две строки, я бы об этом не беспокоился.

Однако, если у вас много конкатенаций, или у вас есть цикл, то вы определенно хотите принять меры предосторожности. В мире Java это означает, что вы используете StringBuffer вместо объединения строк.

На самом деле, вероятно, 3. константная строка для "до свидания", константная строка для "жестокого мира", а затем новая строка для результата.

Вы можете узнать наверняка, посмотрев на сгенерированный код. Это зависит от компилятора (и, на самом деле, от языка, это не очевидно), но вы можете прочитать вывод g++, используя флаг -a (я думаю, проверьте страницу man), чтобы получить промежуточный код,

Будьте осторожны, потому что компилятор может сделать несколько очень разных оптимизаций, когда строковые значения известны во время компиляции. Если используемые вами строки неизвестны до времени выполнения (извлеченные из файла конфигурации, базы данных или пользовательского ввода), вы увидите совсем другой IL.

Если компилятор "умный", это будет только одна строка с "прощай, жестокий мир!"

Другие вопросы по тегам