Неизменяемость струны

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

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

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

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

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

Ответ 1

У компилятора есть специальная обработка для конкатенации строк, поэтому второй пример - это только строка one. И "интернирование" означает, что даже если вы запустили эту строку 20000 раз, остается еще одна строка.

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

.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), компилятор уже сделал это для вас.

Ответ 2

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

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


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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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