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

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

12 голосов
/ 16 декабря 2008

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

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

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

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

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

Ответы [ 9 ]

21 голосов
/ 16 декабря 2008

Компилятор имеет специальную обработку для конкатенации строк, поэтому вторым примером является только одна строка. И «интернирование» означает, что даже если вы запустите эту строку 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), компилятор уже сделал это для вас.

3 голосов
/ 16 декабря 2008

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

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


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

0 голосов
/ 17 декабря 2008

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

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

0 голосов
/ 16 декабря 2008

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

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

0 голосов
/ 16 декабря 2008

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

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

0 голосов
/ 16 декабря 2008

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

0 голосов
/ 16 декабря 2008

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

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

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

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

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

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

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

0 голосов
/ 16 декабря 2008

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

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

0 голосов
/ 16 декабря 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...